Java 抽象类


用abstract修饰的类叫做抽象类,抽象类有以下一些规则:

  1. 抽象类可以包含抽象方法也可以不包含抽象方法
  2. 如果一个类包含了一个或多个抽象方法时,该则类被限定必须是抽象的
  3. 抽象类不能被实例化
  4. 如果从一个抽象类继承,并想创建该新类的对象,那么该对象必须为基类中的所有抽象方法提供定义。

创建抽象类和抽象方法非常有用,因为他们可以使类的抽象性明确起来,并告诉用户和编译器打算怎样来使用他们。抽象类是很有用的重构工具,它可以很容易将公共方法沿着继承层次结构向上移动,示例如下:

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里给相关的接口添加新的方法及实现。然而,对于已经发布的版本,是没法在给接口添加新方法的同时不影响已有的实现。所以引进的默认方法。他们的目的是为了解决接口的修改与现有的实现不兼容的问题

另外还有以下一些不同的地方:

  1. 抽象类不可以多重继承(其实使用内部类也可以实现),而接口可以
  2. 抽象类和接口所反映出的设计理念不同。其实抽象类表示的是"is-a"关系,接口表示的是"like-a"关系
  3. 接口中定义的变量默认是public static final型,且必须给其初值,所以实现类中不能重新定义,也不能改变其值;抽象类中的变量默认是 friendly 型,其值可以在子类中重新定义,也可以重新赋值。
Copyright © jverson.com 2019 all right reserved,powered by Gitbook 20:28

results matching ""

    No results matching ""