Java也写了10年多了,先说说个人的感悟吧,想看面试答案直接翻到本文结尾。
个人感悟
Java语言本身有许多借鉴C++优点,同时克服C++复杂性的地方,例如接口的发明。C++里面是没有接口的,但是可以定义抽象类,然后支持多重继承。关于多重继承的弊端,可以自行搜索。Gosling为了克服多重继承的弊端,直接限制了Java只能是单根继承,即一个类只能继承一个父类。像这种只有方法没有属性的抽象类,一个类可以支持多个不会有影响,因此单独为它设计一个接口的语法。反观C++、Python这种具有多重继承能力的,是不需要接口的。
由于单根继承的特性,给一个类写上extends
基本相当于嫁出去的女儿泼出去水,只有一次机会而且还改不了。所以如果你有机会设计一些公共组件,一定要尽可能的避免继承关系,粗暴的说,能不用就别用。
所有的抽象类都可以被改造成普通类,然后把抽象方法提取成接口,让外面通过构造方法或者方法参数传给你。例如:java.lang.Thread
,可以继承它重写run方法,也可以实例化的时候传一个Runnable
接口进去。
抽象类的适用场景其实只有一种。以前我们学习字形结构的时候肯定学过全包围结构吧,例如"国,围,困,囚"。写得时候呢,抽象类就负责实现外面的方框,"玉、韦、木、人"就交给抽象方法去逐个实现。如果是半包围结构呢?例如:“闪,闯,闲,间“,或者”区,凶“这种,你可以仔细想想需不需要抽象类?需不需要继承关系?
然后说说接口。
从Java8开始,接口语法得到增强,一些以前必须用抽象类的,现在都可以改造为接口了。例如java.lang.Number
类,这个抽象类就没有成员属性。只是shortValue()
方法默认调用(short)intValue();
为了重用这么一两行代码,才用了抽象类。
接口是个好东西,初学Java时授业恩师跟我讲了这样的一个例子:飞机能飞,小鸟能飞,神仙也能飞,这三个你能设计一个父类吗?好像八竿子打不着啊。但是他们确有一个共同的行为:飞。。。 噢~原来接口封装的是相同的行为。所以是不是马上就能体会接口的作用了?
看不懂吗?没有关系,我知道你可能只是想知道开车时油门和脚刹哪个在左边哪个在右边,我给你讲的是如何使用油门和刹车实现漂移!
以下是标准答案
抽象类和接口的相同点
- 都不能被实例化
- 接口的实现类或抽象类的子类都只有实现了接口或抽象类中的方法后才能实例化
抽象类和接口的区别:
-
抽象类中可以有普通成员变量,接口中没有普通成员变量
-
抽象类和接口中都可以包含静态成员变量,抽象类中的静态成员变量的访问类型可以任意,但接口中定义的变量只是public static final 常量类型,并且默认即为常量类型。
-
抽象类可以有构造方法,接口中不能有构造方法
-
一个类可以实现多个接口,但只能继承一个抽象类
- 也只可以说,java是单根继承,一个类只能有一个父类,但是可以实现很多接口(最多255个)
-
抽象类中的抽象方法的访问类型可以是 public,protected ,但接口中的抽象方法只能是 public 类型的
以下说法从Java9开始已经不算正确了
-
接口中的方法默认就是public abstract
-
抽象类中可以包含非抽象的普通方法,接口中的所有方法必须都是抽象的,不能有非抽象的普通方法。
-
抽象类中可以包含静态方法,接口中不能包含静态方法
- java8开始接口中可以定义public static和public default方法
- java9开始接口中可以定义private static和private方法