Java中的接口与抽象类

抽象类和接口都是用来体现OOP中的抽象概念,都可以用来实现多态。

1. 抽象类

抽象类表达的是“is-a”的关系,是对多个具体类公共部分的抽象,定义了子类是什么(如Bird、Duck本质上都是Animal,即可以将其抽象为Animal类),由于抽象类没有足够的信息,是不完整的,所以必须由具体的子类来继承它并实现抽象方法。

抽象类定义

如果一个类含有抽象方法(abstact修饰的方法),则其为抽象类,在class关键字前使用abstract进行修饰。抽象类是为了继承而存在的,即抽象类不能直接创建实例,必须通过子类继承并实现其抽象方法。抽象类中并不只有抽象方法,还可以有提供实现的具体方法和成员变量。

抽象类特点
  1. 抽象类不能被实例化,必须通过子类继承;
  2. 抽象方法必须为public或protected(如果为private,就不能被子类继承了),默认为public;
  3. abstract不能与final同时修饰抽象类中的class和方法,因为这样就不能被继承和重写了。
  4. 如果一个类继承抽象类,则子类必须实现父类的抽象方法,如果子类没有实现父类的抽象方法,则必须将子类也定义为抽象类。

2. 接口

接口表达的是“has-a”的关系,是对行为的抽象,并不能表达子类的本质特征(即子类是什么),子类实现了接口表面其具有该接口提供的行为,(如有一个Flyable接口,提供fly()方法,Bird实现该接口时,必须实现fly()方法,表明其具有飞行行为)。因为Java不允许多继承,通过实现接口可以间接实现多继承。

  1. 接口的所有方法都不能有具体的实现,即所有方法都是抽象方法(JDK8可以有默认方法实现),可以有成员变量,但会被隐式的指定为public static final,而方法会被隐式地指定为public abstract方法且只能是public abstract方法;
  2. 实现接口的非抽象类必须要实现该接口的所有方法。抽象类可以不用实现。

3. 抽象类和接口区别

抽象类和接口都用来表达面向对象中的抽象概念,都可以作为超类型提供多态的实现。抽象类作为父类对子类中公共的特征进行抽象(所以必须是对具有一组相同概念本质的子类,如都是动物),而接口不用管子类具体是什么,只需要提供行为,对行为进行抽象,如Flyable接口提供飞行行为,Bird和AirPlane都可以实现该接口,并实现其中的飞行方法,但这两个类本质是不同的类。所以Java提供抽象类和接口,一个用来抽象子类是什么(is-a),一个用来抽象子类可以具有哪些行为方法(has-a)。二者可以结合起来使用,实现多个接口。

语法层面
  1. 抽象类可以拥有任意范围的成员数据,同时也可以拥有自己的非抽象方法,但是接口方式中,它仅能够有静态、不能修改的成员数据(但是我们一般是不会在接口中使用成员数据),同时它所有的方法都必须是抽象的。在某种程度上来说,接口是抽象类的特殊化。
  2. 一个类只能继承一个抽象类,可以实现多个接口,从某种程度上说,接口允许Java的多继承。
  3. 接口中不能有静态代码块和静态方法,而抽象类可以有。
设计层面
  1. 抽象层次不同:抽象类是对类的本质特征进行抽象,接口是对行为进行抽象。抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。
  2. 跨域不同:抽象类所跨域的是具有相似特点的类,而接口则可以跨不同的类。继承抽象类的子类必须和其父类在概念本质上是相同的,而实现接口的子类可以不存在任何关系,仅仅是实现了接口定义的契约而已。
  3. 设计层次不同:抽象类是自底向上抽象而来的,接口是自顶向下设计出来的。

举个例子:

门和警报的例子:有一个Door类,具有open()和close()两个行为。我们可以通过抽象类和接口来定义这个概念:

抽象类:

abstract class Door{
    abstract void open();
    abstract void close();
}

接口:

interface Door {
    void open();
    void close();
}

现在要给门加一个报警的功能alarm(),如何实现呢,有两种思路:

  1. 将报警方法放在抽象类里,但是这样一来所有继承于这个抽象类的子类都具备了报警功能,但是并不是所有的门并一定具备报警功能;
  2. 将这三个功能都放在接口里面,需要用到报警功能的类就需要实现这个接口中的open( )和close( ),也许这个类根本就不具备open( )和close( )这两个功能,比如火灾报警器。

从这里可以看出,open()和close()是所有Door的固有方法,所以可以将其抽象出来并在抽象类中定义,而alarm()方法属于附加行为,所以应该将其单独抽象为一个接口,代表具有报警行为,这样不只门可以实现该接口,其他具有报警功能的都可以实现。

所以open()和close()放在抽象类里,alarm()单独用一个接口来表示:

interface Alram {
    void alarm();
}
 
abstract class Door {
    void open();
    void close();
}
 
class AlarmDoor extends Door implements Alarm {
    void oepn() {
      //....
    }
    void close() {
      //....
    }
    void alarm() {
      //....
    }
}

参考:

  1. https://blog.csdn.net/chenssy/article/details/12858267
  2. https://www.cnblogs.com/dolphin0520/p/3811437.html
  3. https://juejin.im/entry/59fa7b07518825076a0c4a0c
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值