Bootstrap

抽象类

5.5.1 抽象方法和抽象类

抽象方法和抽象类的规则:

  • 抽象方法和抽象类必须使用abstract修饰符来定义,有抽象方法的类只能被定义成抽象类,抽象类里可以没有抽象方法,抽象方法不能有方法体。

  • 抽象类不能被实例化,无法使用new关键字来调用抽象类的构造器创建抽象类的实例。

  • 抽象类可以包含成员变量,方法,构造器,初始化类,内部类。抽象类不能用于创建实例,主要是用于被其子类调用

  • 含有抽象方法的类只能被定义成抽象类

抽象方法和空方法体不是同一个概念。public abstract void test();是一个抽象方法。public void test(){}是一个空方法体。

Shape.java

package code.shape;
public abstract class Shape{
    {
        System.out.println("执行Shape的初始化块...");
    }
    private String color;
    public abstract double calPerimeter();
    public abstract String getType();
    public Shape(){
    }
    public Shape(String color){
        System.out.println("执行Shape的构造器...");
        this.color = color;
    }
    public void setColor(String color){
        this.color = color;
    }
    public String getColor(){
        return color;
    }
}

Triangle.java

package code.shape;
import code.shape.*;
public class Triangle extends Shape{
    private double a;
    private double b;
    private double c;
    public Triangle(String color,double a,double b,double c){
        super(color);
        this.setSides(a,b,c);
    }
    public void setSides(double a,double b,double c){
        if(a>=b+c||b>=a+c||c>a+b){
            System.out.println("三角形两边之和必须大于等于第三边");
            return;
        }
        this.a = a;
        this.b = b;
        this.c = c;

    }
    public double calPerimeter(){
        return a+b+c;
    }
    public String getType(){
        return "三角形";
    }

}

Circle.java

package code.shape;
import java.lang.Math;
import code.shape.*;
public class Circle extends Shape{
    private double radius;
    public Circle(String color,double radius){
        super(color);
        this.radius = radius;
    }
    public void setRadius(double radius){
        this.radius = radius;
    }
    public double calPerimeter(){
        return 2*Math.PI*radius;
    }
    public String getType(){
        return getColor() + "圆形";
    }
    public static void main(String []args){
        Shape s1 = new Triangle("黑色",3,4,5);
        Shape s2 = new Circle("红色",4);
        System.out.println(s1.getType());
        System.out.println(s1.calPerimeter());
        System.out.println(s2.getType());
        System.out.println(s2.calPerimeter());
    }
}

执行Shape的初始化块…
执行Shape的构造器…
执行Shape的初始化块…
执行Shape的构造器…
三角形
12.0
红色圆形
25.132741228718345

当使用abstract修饰类时,表明这个类只能被继承;当使用abstract修饰方法时,表明这个方法必须由子类提供实现(即重写)。而final修饰的类不能被继承,final修饰的方法不能被重写。因此final和abstract永远不能同时使用。

static和abstract并不是绝对互斥,static和abstract不能同时修饰某个方法,但可以同时修饰内部类。
abstract方法不能定义为private访问权限。abstract和private不能同时修饰方法。

5.5.2 抽象类的作用

从语义的角度来看,抽象类是从多个具体类中抽象出来的父类,它具有更高层次的抽象。
抽象类体现的就是一种模板模式的设计。
在上述Shape,Circle和Triangle三个类使用了模板模式,父类的普通方法依赖于一个抽象方法,而抽象方法则推迟到子类中实现。

SpeedMeter.java

package code.speed;
public abstract class SpeedMeter{
    private double turnRate;
    public SpeedMeter(){}
    public void setTurnRate(double turnRate){
        this.turnRate = turnRate;
    }
    public abstract double getRadius();
    public double getSpeed(){
        return java.lang.Math.PI * 2 *getRadius() * turnRate;
    }
}

carSpeedMeter.java

package code.speed;
public class carSpeedMeter extends SpeedMeter{
    public double getRadius(){
        return 0.28;
    }
    public static void main(String[] args){
        SpeedMeter sm = new carSpeedMeter();
        sm.setTurnRate(15);
        System.out.println(sm.getSpeed());
    }
}

26.389378290154266

规则:

  • 抽象父类可以只定义需要使用的某些方法,把不能实现的部分方法抽象成抽象方法,留给其子类去实现。
  • 父类中可能包含需要调用其他系列方法的方法,这些被调方法既可以由父类实现,也可以由其子类实现。父类里提供的方法只是定义了一个通用算法,其实现也许并不完全由自身实现,而必须依赖于其子类的辅助。
;