Java 抽象类
用abstract修饰的类叫做抽象类,抽象类有以下一些规则:
- 抽象类可以包含抽象方法也可以不包含抽象方法
- 如果一个类包含了一个或多个抽象方法时,该则类被限定必须是抽象的
- 抽象类不能被实例化
- 如果从一个抽象类继承,并想创建该新类的对象,那么该对象必须为基类中的所有抽象方法提供定义。
创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样来使用他们。抽象类是很有用的重构工具,它可以很容易将公共方法沿着继承层次结构向上移动,示例如下:
public class Music {
static void tune(Instrument i){
i.play();
}
static void tuneAll(Instrument[] e){
for (Instrument instrument : e) {
tune(instrument);
}
}
public static void main(String[] args) {
tuneAll(new Instrument[]{
new Wind(),
new Percussion()
});
}
}
abstract class Instrument{
public abstract void play();
public String waht() {
return "instrument";
}
}
class Wind extends Instrument{
@Override
public void play() {
System.out.println("Wind.play()");
}
@Override
public String waht() {
return "wind";
}
}
class Percussion extends Instrument{
@Override
public void play() {
System.out.println("Percussion.play()");
}
@Override
public String waht() {
return "percussion";
}
}
JDK8中接口的默认方法
另外注意到最新的JDK8中允许接口有默认实现方法,感觉和抽象类功能非常类似,示例如下:
public interface Instrument2 {
default void play(){
System.out.println("Instrument2.play()");
}
//接口的默认方法
default String what() {
return "instrument";
}
//使用内部类进行测试
static class Test implements Instrument2{
static void tune(Instrument2 i){
i.play();
}
static void tuneAll(Instrument2[] e){
for (Instrument2 instrument : e) {
tune(instrument);
}
}
public static void main(String[] args) {
tuneAll(new Instrument2[]{
new Wind2(),
new Percussion2()
});
}
@Override
public void play() {}
}
}
class Wind2 implements Instrument2{
@Override
public void play() {
System.out.println("Wind2.play()");
}
}
class Percussion2 implements Instrument2{
@Override
public String what() {
return "percussion2";
}
}
运行输出如下:
Wind2.play() //重写了接口中的default方法 Instrument2.play() //“继承了”接口中的default方法
以上示例简单说,就是接口可以有实现方法,而且不需要实现类去实现其方法,只需在方法名前面加个default关键字即可。
抽象类与JDK8支持默认方法的接口比较
这时候就要疑问了,这不是抽象类可以干的事么,为什么现在要给接口添加这个功能吗?
首先,之前的接口是个双刃剑,好处是面向抽象而不是面向具体编程,缺陷是,当需要修改接口时候,需要修改全部实现该接口的类,目前的java 8之前的集合框架没有foreach方法,通常能想到的解决办法是在JDK里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题。
另外还有以下一些不同的地方:
- 抽象类不可以多重继承(其实使用内部类也可以实现),而接口可以
- 抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系
- 接口中定义的变量默认是public static final型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。