抽象类
- 如果一个类中包含抽象方法,那么这个类必须声明为抽象类
- 抽象类只能继承而不能被实例化
- 需要符合里氏替换原则:
- 子类必须实现父类的抽象方法,但不得重写(但是可以重载)父类的非抽象方法
- 子类可以扩展自己的方法
- 当子类重载或实现父类抽象方法时,方法中输入的参数类型要与父类相同或者是其父类(例如父类是ArrayList,子类可以是List)
- 当子类的方法实现父类抽象方法时,方法的返回值类型要与父类相同或者是其子类(例如父类是List,子类可以是ArrayList)
接口
- 在java8之前,接口中定义的方法不能有任何默认实现,这意味着一旦接口添加新的方法,所有实现了该接口的类都要实现新增的方法
- java8开始,接口定义的方法可以像抽象类一样有默认的实现,方法前面需要加default修饰
- 接口中定义的字段和方法默认都是public,不能被定义为private或者protected
- 接口中的字段默认都是static final
抽象类与接口比较
- 抽象类必须要符合里氏替换原则,也就是子类对象必须要能够替换所有父类对象;而接口只是不同类之间共同的约定,实现该接口的类并不需要遵守里氏替换原则;
- 一个类可以实现多个接口,但是只能继承一个抽象类
- 接口的字段只能是static final,而且方法只能是public,而抽象类却没有这个限制
抽象类和接口如何选择?
使用接口的情况:
- 需要不相关的类都实现同一个功能,例如飞机和鸟它们一个是交通工具一个是动物,但是都可以实现Fly这个功能
- 需要多继承时可以使用接口代替
使用抽象类的情况:
- 在几个相关的类中有公共方法实现或者定义算法骨架(设计模式中的模板方法模式)
- 需要能控制继承来的成员的访问权限,而不都是为public
- 需要继承非静态和非常量字段
总结
在大多数情况下是优先选择接口的,因为接口没有抽象类那么多层次结构要求,可以很灵活的给某一个类添加行为,而且从java8开始也支持定义默认方法,使得修改接口影响的范围降低。