这个在面试过程中经常被问到,学习了很多帖子,总结如下
1、abstract关键字
1)修饰类
- 此类不能实例化
- 一定有构造器,便于子类调用
- 我们开发时,都会提供抽象类的子类
2)修饰方法
- 只有方法声明,无方法体
- 包含抽象方法的类一定是抽象类,抽象类中可以没有抽象方法
- 若父类有抽象方法,则子类要么重写所有抽象方法,要么也是抽象类
//有抽象方法的类必须声明为abstract
public abstract class Test1{
//抽象方法不能有“{}”
public abstract void f();
}
抽象类和抽象方法都使用 abstract 关键字进行声明。
2、接口
用Interface修饰,是抽象类的延申,在Java8之前可以看成一个完全抽象的类,也就是说不能有任何的方法的实现。从JDK8开始,接口也可以拥有默认的方法实现,这是因为不支持默认方法的接口的维护成本太高了。在JDK8之前,如果一个接口想要添加新的方法,那么要修改所有实现了该接口的类。
1)接口的特性(接口中有且仅有以下四种定义)
- 抽象方法:被隐式的指定为 public abstract(只能是 public abstract,可以省略),抽象方法只能由实现接口的类来实现。
- 全局常量:被隐式的指定为 public static final 变量(并且只能是 public,用 private 修饰会报编译错误)。
JDK8以后可以定义静态方法和默认方法:
- 静态方法:只能通过接口来调用
- 默认方法:通过实现类的实例可以调用接口中的默认方法,实现类也可以重写接口中的默认方法
2)构造器:
接口中没有构造器,意味着接口不能实例化;
3)接口实现:
类实现了接口就需要覆盖接口中所有的抽象方法,否则类为抽象类;
4)类优先原则:
如果子类继承的父类和实现的接口声明了同名同参数的方法,那么子类在没有重写此方法的情况下,默认调用父类的同名同参数方法。
3、抽象类和接口的区别
1)语法层次
- 抽象类中可以有普通方法和抽象方法(public abstract),接口中的方法全是抽象方法(JDK8之后有静态方法和默认方法);
- 抽象类中可以有普通成员变量,接口中没有普通成员变量,只能有全局常量(public static final)
- 一个类只能继承一个类,但可以实现多个接口
2)设计层次
- 抽象类是对整个类整体进行抽象,包括属性、行为,但是接口却是对类局部(行为)进行抽象。
- 抽象类所体现的是一种继承关系,要想使得继承关系合理,父类和派生类之间必须存在 “is-a” 关系,即父类和派生类在概念本质上应该是相同的,需满足里氏替换原则。对于接口则不然,并不要求接口的实现者和接口定义在概念本质上是一致的,仅仅是实现了接口定义的契约而已, “like-a” 的关系。
ps.里氏替换原则:派生类(子类)对象可以在程序中代替其基类(父类)对象。
4、使用选择
1)使用接口
- 需要让不相关的类都实现一个方法,例如不相关的类都可以实现 Compareable 接口中的 compareTo() 方法;
- 需要使用多重继承。
2)使用抽象类
- 需要在几个相关的类中共享代码。
- 需要能控制继承来的成员的访问权限,而不是都为 public。
- 需要继承非静态和非常量字段