接口和抽象类的不同,就像你和我的不同一样;
但是抽象类和接口的不同能说尽,
而你与我之间,言不尽也道不明。
1. 好吧,我们开始正题,先说抽象类
我把我的理解写在最前:
抽象类就是普通的类加上了abstract修饰,原来的普通类中的代码不受影响,也就是说普通类中能写的东西抽象类中都能写,能不能调用就要另说了。
我们先看一个普通的类
public class Student {
private String name;
private int id;
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
}
下面我们把它加上abstract修饰
我们发现,已经写好的代码不受影响,不会报红线
但是其中的字段已经不能再生效,因为抽象类不能实例化对象
public abstract class Student {
private String name;
private int id;
public Student(String name, int id) {
this.name = name;
this.id = id;
}
public String getName() {
return name;
}
}
加上 abstract 修饰的类,其中可以添加抽象方法,这便是它与普通类中拓展出来的功能。
比如我们添加一个抽象方法
//其他代码
public abstract void play();
我们大概理解了抽象类,那么我们下边对它做一个用法总结
用法总结 ↓(建议在读一下开头的我的理解加深印象)
- 抽象类不能被实例化,构造方法用于子类在调用时用于初始化父类。(想实例化直接给你报红线)
- 抽象类中不一定含有抽象方法,但是含有抽象方法一定是抽象类。
- 抽象类的子类要么实现所有抽象方法,要么子类继续被标记为抽象类。
- 抽象类中构造方法和静态方法不能被声明为抽象(可以用抽象类名直接调用静态方法)。
2. 聊完了抽象类我们来说说接口
我们来看张图吧,这样更好理解
在JDK1.8加入静态方法,这种用法也比较常见,比如我们用过Collection接口调用它的静态方法size()。(Collection/Collections是一对常见的接口和实用工具类) 参考自《Java核心技术 卷I》
2.1 容我聊聊default修饰的默认方法吧
- 若对已有的接口增加default方法,因为default方法可以不被子类实现类实现,所以这样就避免出现“接口新增一个方法,对实现类都要进行修改”的情况,因为在代码量很大的情况下也很麻烦。
2.1.2 但是这样也出现了默认方法冲突的问题(《Java核心技术 卷I》
- 容我来描述一下第一个问题,如果一个接口提供了一个默认方法,另一个接口也提供了一个同名且参数类型相同的默认方法,现在有一个类同时实现了这两个接口,那么在实现类中必须覆盖这个方法来解决这个冲突,因为它不会自己选择一个方法执行。
- 我再来描述第二个问题,一个接口提供了一个默认方法,另一个是一个父类中的同名同参数类型默认方法,一个类同时继承了父类又实现了接口,那么会根据父类优先原则,接口中的默认方法会被忽略,直接采用父类中的默认方法。
3. 下面我们来聊它们的不同
必须说出来第1点
- 每个类只能继承一个抽象类,强调的是“IS-A”关系,也就是从属关系;而每个类可以实现多个接口,更强调的则是具有接口的功能。
- 抽象类中,可以又构造器,用来完成抽象类的初始化;接口中没有构造器
- 抽象类中可以有普通方法,抽象方法,静态方法,四种权限修饰符都可以用;接口中只有抽象方法,静态方法和默认方法(default),权限都是public(在JDK1.8)
- 抽象类中可以有成员变量(但是没什么用)和静态变量;接口中的变量都是常量,默认有 public static final 修饰