1、定义
1) 抽象类(abstract class)
官方定义:如果一个类没有包含足够多的信息来描述一个具体的对象,这样的类就是抽象类。简单来说就是使用abstract修饰符修饰的类。
实际点来说,一个抽象类不能实例化,因为“没有包含足够多的信息来描述一个具体的对象”。但终归属于类,所以仍然拥有普通类一样的定义。依然可以在类的实体(直白点就是能在{}里面)定义成员变量,成员方法,构造方法等。但是可以使用抽象类类型的变量引用其实现类,如:抽象类A,其实现类为B,则可以:A a = new B(); 。
那么可能初学者会问:既然不能实例化,那么在类里面定义成员方法,成员变量有什么用。
抽象类在实际应用中,更多的是因为类中有抽象方法。抽象方法:只声明,不实现。具体的实现由继承它的子类来实现。实际点就是:被abstract修饰的方法,只有方法名没有方法实现,具体的实现要由子类实现。方法名后面直接跟一个分号,而不是花括号。例如:public abstract int A();
一个类中含有抽象方法(被abstract修饰),那么这个类必须被声明为抽象类(被abstract修饰)。
有关抽象类的基础知识可以查看 www.runoob.com/java/java-abstraction.html
2)接口(interface):
官方定义:接口在java中是一个抽象类型,是抽象方法的集合。一个类通过实现接口的方式,从而继承接口的抽象方法。
从定义上看,接口是个集合,并不是类。类描述了属性和方法,而接口只包含方法(未实现的方法)。接口和抽象类一样不能被实例化,因为不是类。但是接口可以被实现(使用 implements 关键字)。实现某个接口的类必须在类中实现该接口的全部方法。虽然接口内的方法都是抽象的(和抽象方法很像,没有实现)但是不需要abstract关键字。
接口中没有构造方式(因为接口不是类),不能用于实例化对象
接口中的方法必须是抽象的(不能实现)(jdk8后有变化,后面介绍)
接口中除了static、final变量,不能有其他变量
- 接口中每一个方法也是隐式抽象的,接口中的方法会被隐式的指定为 public abstract(只能是 public abstract,其他修饰符都会报错)。
- 接口中可以含有变量,但是接口中的变量会被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
接口支持多继承(一个类可以实现多个接口)
有关接口的更详细的基础知识可以参考: www.runoob.com/java/java-interfaces.html
2、抽象类和接口的区别
1)从设计目的上来说,二者有如下的区别:
接口体现的是一种自上而下的行为规范。对于接口的实现者而言,接口规定了实现者必须向外提供哪些服务;对于接口的调用者而言,接口规定了调用者可以调用哪些服务,以及如何调用这些服务,不需要关心接口的实现。当在一个程序中使用接口时,接口是多个模块间的耦合标准;当在多个应用程序之间使用接口时,接口是多个程序之间的通信标准。
抽象类体现的是一种自下而上的模板式设计。抽象类作为多个子类的抽象父类,可以被当成系统实现过程中的中间产品,这个中间产品已经实现了系统的部分功能,但这个产品依然不能当成最终产品,必须有更进一步的完善,这种完善可能有几种不同方式。
2)从使用方式上来说,二者有如下的区别:
1、默认的方法实现:抽象类可以有默认的方法实现完全是抽象的。接口根本不存在方法的实现。
抽象类中可以有已经实现了的方法,也可以有被abstract修饰的方法(抽象方法),因为存在抽象方法,所以该类必须是抽象类。但是接口要求只能包含抽象方法,抽象方法是指没有实现的方法。所以就不能像抽象类那么无赖了,接口就根本不能存在方法的实现。
2、实现抽象类使用extends关键字来继承抽象类。如果子类不是抽象类的话,它需要提供抽象类中所有声明的方法的实现。子类使用关键字implements来实现接口。它需要提供接口中所有声明的方法的实现。
抽象类虽然不能实例化来使用,但是可以被继承,让子类来具体实现父类的所有抽象方法。有点老子没完成的梦想交给儿子来完成,但是如果子类将抽象方法没有全部实现,就必须把自己也修饰成抽象类,交于继承它的子类来完成实现。就相当于,儿子能力不够也没完成老爹的梦想,现在儿子等着再生儿子(被继承),然后让孙子去完成。以此类推,知道没有抽象函数。
接口的实现,通过implements关键字。实现该接口的类,必须把接口中的所有方法给实现。不能再推给下一代。和抽象类相比,抽象类是将梦想传给家族,一代一代去完成。那么接口就是掌门人找大师兄来完成帮派的鸿星伟业,这时候就只有一次希望,要么有能力就实现,没能力就不要接。
3)抽象类可以有构造器,而接口不能有构造器
这个原因很简单,我们回到双方的定义上来,抽象类再怎么流氓无赖也好,终究是属于类,就天生享有类的所有特性(但是不能实例化),当然包括类的构造方法,也就是构造器。
但是接口是所有抽象方法的集合,注意,是集合,不是类。当然没有构造方法一说,更别提什么构造器了。
4、抽象方法可以有public、protected和default这些修饰符,但是接口方法默认修饰符是public。你不可以使用其它修饰符。
抽象类的目的就是被继承,抽象方法就是为了被重写,所以肯定不能用private修饰符,肯定是可以用public的。但是protected和default也是可以的。
接口就有且只有一个public修饰。
(是不是感觉抽象类像小儿子各种耍无赖,接口就像私生子,说什么只能是什么)
5、抽象类在java语言中所表示的是一种继承关系,一个子类只能存在一个父类,但是可以存在多个接口。(单继承多实现)
java在类的继承上并没有多继承。抽象类属于类,所以可以被继承。但子类只能继承一个父类。java为了实现多继承,使用了接口。一个类可以实现多个接口。继承就好比生了孩子,只能有一个爹,但是这个孩子可以学语文,学数学,学英语等等很多东西,而语文、数学、英语就相当于接口。
总的来说,因为java中抽象类只有单继承,接口就可以实现多继承。
6、抽象方法比接口速度要快
接口是稍微有点慢的,因为它需要时间去寻找在类中实现的方法。
记住抽象方法是小儿子,从小吃的好所以跑的快,接口是私生子,从小日子苦,营养不良。
7、如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。
如果你往抽象类中添加新的方法,你可以给它提供默认的实现。因此你不需要改变你现在的代码。 如果你往接口中添加方法,那么你必须改变实现该接口的类。
注意:
1、JDK 1.8 以后,接口里可以有静态方法和方法体了,静态方法可以直接用接口名调⽤,实现类和实现是不可以调用的。如果同时实现两个接口,接口中定义了⼀样的默认方法,则必须重写,不然会报错。
2、JDK 1.8 以后,接口允许包含具体实现的方法,该方法称为"默认方法",默认方法使用 default 关键字修饰,更多内容可参考 Java 8 默认方法。
3、JDK 1.9 以后,允许将方法定义为 private,使得某些复用的代码不会把方法暴露出去。更多内容可参考 Java 9 私有接口方法。
参考:
作者:IT废柴
链接:https://www.jianshu.com/p/038f0b356e9a
来源:简书