疯狂java


您现在的位置: 疯狂软件 >> 新闻资讯 >> 正文

Java笔记之抽象、接口、多态、异常


 

   

  抽象、接口、多态、异常

  一、抽象类

  当多个类中出现相同功能,但是功能主体不同,

  这是可以进行向上抽取。这时,只抽取功能定义,而不抽取功能主体。

  抽象类的特点:

  1,抽象方法一定在抽象类中。

  2,抽象方法和抽象类都必须被abstract关键字修饰。

  3,抽象类不可以用new创建对象。因为调用抽象方法没意义。

  4,抽象类中的抽象方法要被使用,必须由子类复写起所有的抽象方法后,建立子类对象调用。

  如果子类只覆盖了部分抽象方法,那么该子类还是一个抽象类。

  抽象类和一般类没有太大的不同。

  该如何描述事物,就如何描述事物,只不过,该事物出现了一些看不懂的东西。

  这些不确定的部分,也是该事物的功能,需要明确出现。但是无法定义主体。

  通过抽象方法来表示。

  抽象类比一般类多个了抽象函数。就是在类中可以定义抽象方法。

  抽象类不可以实例化。

  特殊:抽象类中可以不定义抽象方法,这样做仅仅是不让该类建立对象。

  abstract 关键字,和哪些关键字不能共存。(private final static)

  final:被final修饰的类不能有子类。而被abstract修饰的类一定是一个父类。

  private: 抽象类中的私有的抽象方法,不被子类所知,就无法被复写。

  而抽象方法出现的就是需要被复写。

  static:如果static可以修饰抽象方法,那么连对象都省了,直接类名调用就可以了。

  可是抽象方法运行没意义。

  抽象类中是否有构造函数?

  有,抽象类是一个父类,要给子类提供实例的初始化。

  java中普通类继承,抽象类继承,接口类继承,子类一定要重写父类中的方法吗?

  不一定。

  1. 普通类继承,并非一定要重写父类方法。

  2. 抽象类继承,如果子类也是一个抽象类,并不要求一定重写父类方法。如果子类不是抽象类,则要求子类一定要实现父类中的抽象方法。

  3. 接口类继承。如果是一个子接口,可以扩展父接口的方法;如果是一个子抽象类,可以部分或全部实现父接口的方法;如果子类不是抽象类,则要求子类一定要实现父接口中定义的所有方法。

  二、接口

  Interface

  过度:初期理解,可以认为是一个特殊的抽象类

  当抽象类中的方法都是抽象的,那么该类可以通过接口的形式来表示。

  class用于定义类

  interface 用于定义接口。Implements用来继承(实现)接口

  接口定义时,格式特点:

  1,接口中常见定义:常量,抽象方法。

  2,接口中的成员都有固定修饰符。

  常量:public static final

  方法:public abstract

  记住:接口中的成员都是public的。

  接口:是不可以创建对象的,因为有抽象方法。

  需要被子类实现,子类对接口中的抽象方法全都覆盖后,子类才可以实例化。

  否则子类是一个抽象类。

  接口可以被类多实现,也是对多继承不支持的转换形式。java支持多实现。

  接口是队伍保留的规则;

  接口是程序的功能扩展;

  接口可以用来多实现;

  类与接口之间是实现关系,而且类可以继承一个类的同时实现多个接口。;

  接口与接口之间可以有继承关系。Implements

  抽象类和接口的区别:

  1:抽象类只能被继承extends,而且只能单继承。

  接口需要被实现implements,而且可以多实现。

  2:抽象类中可以定义非抽象方法,子类可以直接继承使用。

  接口中都有抽象abstract方法,需要子类去实现。

  3:抽象类使用的是 is a 关系。

  接口使用的 like a 关系。

  4:抽象类的成员修饰符可以自定义。

  接口中的成员修饰符是固定的。全都是public的。

  接口型引用指向自己的子类对象。

  三、多态

  1,多态的体现

  父类的引用指向了自己的子类对象。

  父类的引用也可以接收自己的子类对象。

  2,多态的前提

  必须是类与类之间有关系。要么继承,要么实现。

  通常还有一个前提:存在覆盖。

  3,多态的好处

  多态的出现大大的提高程序的扩展性。

  4,多态的弊端:

  提高了扩展性,但是只能使用父类的引用访问父类中的成员。

  5,多态的应用

  abstract class Animal{

  abstract void eat();

  }

  class Cat extends Animal{

  public void eat() {

  System.out.println("吃鱼");

  }

  }

  class Dog extends Animal{

  public void eat() {

  System.out.println("吃骨头");

  }

  }

  class Pig extends Animal{

  public void eat() {

  System.out.println("饲料");

  }

  }

  //-----------------------------------------

  class DuoTaiDemo {

  public static void main(String[] args) {

  function(new Cat());

  function(new Dog());

  function(new Pig());

  }

  public static void function(Animal a){//Animal a = new Cat();

  a.eat();

  //a.catchMouse();

  }

  }

  1).类型转型

  Animal a = new Cat();//类型提升。 向上转型。

  //如果想要调用猫的特有方法时,如何操作?

  //强制将父类的引用。转成子类类型。向下转型。

  ///Cat c = (Cat)a;// a始终是一只猫。

  //c.catchMouse();

  下面这个违背了自然的原则,父类不可以强制转换为子类

  //千万不要出现这样的操作,就是将父类对象转成子类类型。

  //我们能转换的是父类应用指向了自己的子类对象时,该应用可以被提升,也可以被强制转换。

  //多态自始至终都是子类对象在做着变化。

  Animal a = new Animal();

  Cat c = (Cat)a;//a 始终是动物,等于是把猫提升了。a吃的是鱼,不能吃菜什么的。

  2).instanceof : 用于判断对象的类型。 对象 intanceof 类型(类类型 接口类型)

  if(a instanceof Cat){

  Cat c = (Cat)a;

  c.catchMouse();

  }

  else if(a instanceof Dog){

  Dog c = (Dog)a;

  c.kanJia();

  }

  3).多态中成员的特点:

  在多态中成员函数的特点:

  在编译时期:参阅引用型变量所属的类中是否有调用的方法。如果有,编译通过,如果没有编译失败。

  在运行时期:参阅对象所属的类中是否有调用的方法。

  简单总结就是:成员函数在多态调用时,编译看左边,运行看右边。

  也就是说:

  Animal a = new Cat();//类型提升。 向上转型。

  a.eat();//可以编译成功

  a.catchMouse();//编译不成功,因为编译时a属于Animal没有catchMouse()的功能

  //如果想要调用猫的特有方法,就得强制将父类的引用。转成子类类型。向下转型。

  Cat c = (Cat)a;

  c.catchMouse();

  在多态中,成员变量的特点:

  无论编译和运行,都参考左边(引用型变量所属的类)。

  也就是说,子类中的成员变量没法覆盖父类。

  在多态中,静态成员函数的特点:

  无论编译和运行,都参考做左边。

  4).复写

  object类是所有类的最跟类,其中包括的函数一般都需要复写拿来用。

  Class Demo{

  Int num;

  Demo(int num){

  this.num=num;

  }

  public boolean equals(Object obj){

  if(!(obj intanceof Demo))

  return falst;

  Demo d= (Demo)obj;

  return this.num==d.num

  }

  }

  Public String toString(){

  return getClass().getName+’@’+Interger.toHexString(hashCode());

  }

  5).内部类

  将一个类定义在另一个的里面,对里面那个类就称为内部类(嵌套类)

  内部类的访问规则:

  1,内部类可以直接访问外部类中的成员,包括私有。

  之所以可以直接访问外部类中的成员,是因为内部类中持有了一个外部类的引用,格式 外部类名.this

  2,外部类要访问内部类,必须建立内部类对象。

  访问格式:

  1,当内部类定义在外部类的成员位置上,而且非私有,可以在外部其他类中。

  可以直接建立内部类对象。

  格式

  外部类名.内部类名 变量名 = 外部类对象.内部类对象;

  Outer.Inner in = new Outer().new Inner();

  2,当内部类在成员位置上,就可以被成员修饰符所修饰。

  比如,private:将内部类在外部类中进行封装。

  static:内部类就具备static的特性。

  当内部类被static修饰后,只能直接访问外部类中的static成员。出现了访问局限。

  在外部其他类中,如何直接访问static内部类的非静态成员呢?

  new Outer.Inner().function();

  在外部其他类中,如何直接访问static内部类的静态成员呢?

  uter.Inner.function();

  注意:当内部类中定义了静态成员,该内部类必须是static的。

  当外部类中的静态方法访问内部类时,内部类也必须是static的。

  当描述事物时,事物的内部还有事物,该事物用内部类来描述。

  因为内部事务在使用外部事物的内容。

  内部类定义在局部时,

  1,不可以被成员修饰符修饰

  2,可以直接访问外部类中的成员,因为还持有外部类中的引用。

  但是不可以访问它所在的局部中的变量。只能访问被final修饰的局部变量。

  6)匿名内部类

  匿名内部类:

  1,匿名内部类其实就是内部类的简写格式。

  2,定义匿名内部类的前提:

  内部类必须是继承一个类或者实现接口。

  3,匿名内部类的格式:new 父类名&接口名(){ 定义子类成员或者覆盖父类方法 }.方法。

  4,其实匿名内部类就是一个匿名子类对象。而且这个对象有点胖。 可以理解为带内容的对象。

  5,匿名内部类中定义的方法最好不要超过3个。

  匿名内部类的使用场景:

  当函数的参数是接口类型引用时,如果接口中的方法不超过3个。可以通过匿名内部类来完成参数的传递。

  其实就是在创建匿名内部类时,该类中的封装的方法不要过多,最好两个或者两个以内。

  四、异常

  异常处理原则:功能抛出几个异常,功能调用如果进行try处理,需要与之对应的catch处理代码块,这样的处理有针对性,抛几个就处理几个。

  特殊情况:try对应多个catch时,如果有父类的catch语句块,一定要放在下面。

  throw 和throws关键字的区别:

  throw用于抛出异常对象,后面跟的是异常对象;throw用在函数内。

  throws用于抛出异常类,后面跟的异常类名,可以跟多个,用逗号隔开。throws用在函数上。

  Throwable

  |–Error错误

  |–Exception异常

  对于严重的,java通过Error类进行描述。

  对于Error一般不编写针对性的代码对其进行处理。

  对与非严重的,java通过Exception类进行描述。

  对于Exception可以使用针对性的处理方式进行处理。

  1).对多异常的处理。

  1,声明异常时,建议声明更为具体的异常。这样处理的可以更具体。

  2,对方声明几个异常,就对应有几个catch块。不要定义多余的catch块。

  如果多个catch块中的异常出现继承关系,父类异常catch块放在最下面。

  建立在进行catch处理时,catch中一定要定义具体处理方式。

  不要简单定义一句 e.printStackTrace(),

  也不要简单的就书写一条输出语句。

  2).自定义异常:

  因为项目中会出现特有的问题,

  而这些问题并未被java所描述并封装对象。

  所以对于这些特有的问题可以按照java的对问题封装的思想。

  将特有的问题。进行自定义的异常封装。

  当在函数内部出现了throw抛出异常对象,那么就必须要给对应的处理动作。

  要么在内部try catch处理。

  要么在函数上声明让调用者处理。

  一般情况在,函数内出现异常,函数上需要声明。

  如何定义异常信息呢?

  因为父类中已经把异常信息的操作都完成了。

  所以子类只要在构造时,将异常信息传递给父类通过super语句。

  那么就可以直接通过getMessage方法获取自定义的异常信息。

  自定义异常:

  必须是自定义类继承Exception。

  继承Exception原因:

  异常体系有一个特点:因为异常类和异常对象都被抛出。

  他们都具备可抛性。这个可抛性是Throwable这个体系中独有特点。

  只有这个体系中的类和对象才可以被throws和throw操作。

  throws和throw的区别

  throws使用在函数上。

  throw使用在函数内。

  throws后面跟的异常类。可以跟多个。用逗号隔开。

  throw后跟的是异常对象。

  3).RuntimeException使用不用声明直接可以throw RuntimeException();

  Exceptoin中有一个特殊的子类异常RuntimeException 运行时异常。

  如果在函数内容抛出该异常,函数上可以不用声明,编译一样通过。

  如果在函数上声明了该异常。调用者可以不用进行处理。编译一样通过;

  之所以不用在函数声明,是因为不需要让调用者处理。

  当该异常发生,希望程序停止。因为在运行时,出现了无法继续运算的情况,希望停止程序后,

  对代码进行修正。

  自定义异常时:如果该异常的发生,无法在继续进行运算,

  就让自定义异常继承RuntimeException。

  对于异常分两种:

  1,编译时被检测的异常。

  2,编译时不被检测的异常(运行时异常。RuntimeException以及其子类)