16-抽象类及接口

抽象类
如果一个class定义了方法,但没有具体执行代码,这个方法就是抽象方法,抽象方法用abstract修饰。这个抽象方法无法执行,因此这个类也必须申明为抽象类(abstract class)
抽象类本身被设计是只能用于被继承,强迫子类实现其定义的抽象方法。因此,抽象方法实际上相当于定义了“规范”。
//Person类定义了抽象方法run(),那么,在实现子类Student的时候,就必须覆写run()方法
public class Main {
    public static void main(String[] args) {
        Person p = new Student();
        p.run();
    }
}

abstract class Person {
    public abstract void run();
}

class Student extends Person {
    @Override
    public void run() {
        System.out.println("Student.run");
    }
}


注意:父类Person的run()方法没有实际意义,也不能去掉父类的run()方法。去掉父类的run()方法,就失去了多态的特性。

面向抽象编程

当我们定义了抽象类Person,以及具体的Student、Teacher子类的时候,我们可以通过抽象类Person类型去引用具体的子类的实例,这种引用抽象类的好处在于,我们对其进行方法调用,并不关心Person类型变量的具体子类型。
这种尽量引用高层类型,避免引用实际子类型的方式,称之为面向抽象编程。
Person s = new Student();
Person t = new Teacher();

个人理解:将子类向上转型为父类,而父类中自定义 “规范”,具体的实现全都由子类覆写,由于“规范” 的存在,整个继承树中针对某一类型的方法签名完全相同,那么在具体运行过程中的,只需引用父类,而无需关心子类的具体实现。

接口
在抽象类中,抽象方法本质上是定义接口规范:即规定高层类的接口,从而保证所有子类都有相同的接口实现,这样,多态就能发挥出威力。
如果一个抽象类没有字段,所有方法全部都是抽象方法,就可以把该抽象类改写为接口:interfaceabstract class Person {
    public abstract void run();
    public abstract String getName();
}
//改写为 接口interface
interface Person {
    void run();
    String getName();
}

所谓interface,就是比抽象类还要抽象的纯抽象接口,连字段都不能有。因为接口定义的所有方法默认都是public abstract的,所以这两个修饰符都可以省略。
当一个具体的class去实现一个interface时,需要使用implements关键字,在Java中,一个类只能继承自另一个类,不能从多个类继承。但是,一个类可以实现多个interface。
class Student implements Person, Hello { // 实现了两个interface
   private String name;

    public Student(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(this.name + " run");
    }
}


术语
注意区分术语:
Java的接口特指interface的定义,表示一个接口类型和一组方法签名,而编程接口泛指接口规范,如方法签名,数据格式,网络协议等。
抽象类和接口的对比如下:
--------------------------------------------------------------------------        
abstract      class interface 继承      只能extends一个class     可以implements多个interface 字段      可以定义实例字段        不能定义实例字段 抽象方法    可以定义抽象方法        可以定义抽象方法 非抽象方法   可以定义非抽象方法       可以定义default方法
--------------------------------------------------------------------------- 接口继承 一个interface可以继承自另一个interface。interface继承自interface使用extends,它相当于扩展了接口的方法。
interface Hello { void hello(); } interface Person extends Hello { void run(); String getName(); }//Person接口现在可以实现Hello接口的hello方法。 合理理设计interface和abstract class的继承关系,可以充分复用代码。一般来说,公共逻辑适合放在abstract class中,具体逻辑放到各个子类,而接口层次代表抽象程度。 Java的集合类定义的一组接口、抽象类以及具体子类的继承关系: ┌───────────────┐ │ Iterable │接口 └───────────────┘ ▲ ┌───────────────────┐ │ │ Object │父类 ┌───────────────┐ └───────────────────┘ │ Collection │ ▲ └───────────────┘ │ ▲ ▲ ┌───────────────────┐ │ └──────────│AbstractCollection │抽象类 ┌───────────────┐ └───────────────────┘ │ List │ ▲ └───────────────┘ │ ▲ ┌───────────────────┐ └──────────│ AbstractList │ └───────────────────┘ ▲ ▲ │ │ │ │ ┌────────────┐ ┌────────────┐ │ ArrayList │ │ LinkedList │具体子类 └────────────┘ └────────────┘ 在使用的时候,实例化的对象永远只能是某个具体的子类,但总是通过接口去引用它,因为接口比抽象类更抽象(接口回调): List list = new ArrayList(); // 用List接口引用具体子类的实例 Collection coll = list; // 向上转型为Collection接口 Iterable it = coll; // 向上转型为Iterable接口 注意:Iterable接口也可以调用具体子类。 default方法 在接口中,可以定义default方法。通常情况下,继承自某个接口的子类需要对接口中的所有方法覆写,但对于default方法,子类就不必全部修改,只需要在需要覆写的地方去覆写新增方法。 default方法和抽象类的普通方法是有所不同的。因为interface没有字段,default方法无法访问字段,而抽象类的普通方法可以访问实例字段。 public class Main { public static void main(String[] args) { Person p = new Student("Xiao Ming"); p.run(); } } interface Person { String getName(); default void run() { System.out.println(getName() + " run"); } } class Student implements Person { private String name; public Student(String name) { this.name = name; } public String getName() { return this.name; }//无需覆写 run方法 }

猜你喜欢

转载自www.cnblogs.com/nsss/p/11417500.html
今日推荐