Java---抽象類

抽象方法和抽象類

抽象方法和抽象類必須使用abstract修飾符來定義,有抽象方法的類只能被定義成抽象類,抽象類裏可以沒有抽象方法。

抽象方法和抽象類的規則如下:

  • 抽象類必須使用abstract修飾符來修飾,抽象方法也必須使用abstract修飾符來修飾,抽象方法不能有方法體。
  • 抽象類不能被實例化,無法使用new關鍵字來調用抽象類的構造器創建抽象類的實例。即使抽象類裏不包含抽象方法,這個抽象類也不能創建實例。
  • 抽象類可以包含成員變量、方法(普通方法和抽象方法都可以)、構造器、初始化塊、內部類(接口、枚舉)五種成分。抽象類的構造器不能用於創建實例,主要是用於被其子類調用。
  • 含有抽象方法的類(包括直接定義了一個抽象方法;或繼承了一個抽象父類,但沒有完全實現父類包含的抽象方法;或實現了一個接口,但沒有完全實現接口包含的抽象方法三種情況)只能被定義成抽象類。

注意:
歸納起來,抽象類可用“有得有失”4個字來描述。“得”指的是抽象類多了一個能力:抽象類可以包含抽象方法;“失”指的是抽象類失去了一個能力:抽象類不能用於創建實例。

定義抽象方法只需在普通方法上增加abstract修飾符,並把普通方法的方法體(也就是方法後花括號括起來的部分)全部去掉,並在方法後面增加分號即可。

注意:
抽象方法和空方法體的方法不是同一個概念。例如,public abstract void test();是一個抽象方法,它根本沒有方法體,即方法後面沒有一對花括號;但public void test(){}方法是一個普通方法,它已經定義了方法體,只是方法體爲空,即它的方法體什麼也不做,因此這個方法是不可使用abstract來修飾。

定義抽象類只需在普通類上增加abstract修飾符即可。甚至一個普通類(沒有包含抽象方法的類)增加abstract修飾符後也將變成抽象類。

下面定義一個Shape抽象類。

public abstract class Shape {
    {
        System.out.println("執行Shape的初始化塊。。。");
    }

    private String color;

    //定義一個計算周長的抽象方法
    public abstract double calPerimeter();
    //定義一個返回形狀的抽象方法
    public abstract String getType();

    //定義Shape的構造器,該構造器並不是用於創建Shape對象
    //而是被子類調用
    public Shape(){
    }

    public Shape(String color){
        System.out.println("執行Shape的構造器。。。");
        this.color=color;
    }

    public String getColor() {
        return color;
    }

    public void setColor(String color) {
        this.color = color;
    }

}

上面的Shape類裏包含了兩個抽象方法:calPerimeter()和getType(),所以這個Shape類只能被定義成抽象類。Shape類裏既包含了初始化塊,也包含了構造器,這些都不是在創建Shape對象時被調用的,而是在創建其子類的實例時被調用。

抽象類不能用於創建實例,只能當做父類被其他子類繼承。
下面定義一個三角形類,三角形類被定義成普通類,因此必須實現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;
    }

    //重寫Shape類的計算周長的抽象方法
    public double calPerimeter(){
        return a+b+c;
    }

    //重寫Shape類的返回形狀的抽象方法
    public String getType(){
        return "三角形";
    }
}

上面的Triangle類繼承了Shape抽象類,並實現了Shape類中的兩個抽象方法,是一個普通類,因此可以創建Triangle類的實例,可以讓一個Shape類型的引用變量指向Triangle對象。

下面再定義一個Circle普通類,Circle類也是Shape的一個子類。

public class Circle extends Shape {

    private double radius;
    public Circle(String color,double radius){
        super(color);
        this.radius=radius;
    }

    public void SetRadius(){
        this.radius=radius;
    }

    //重寫Shape類的計算周長的抽象方法
    public double calPerimeter(){
        return 2*Math.PI*radius;
    }

    //重寫Shape類的返回形狀的抽象方法
    public String getType(){
        return getColor()+"圓形";
    }
    public static void main(String[] args) {

        Shape s1=new Triangle("黑色", 3, 4, 5);
        Shape s2=new Circle("黃色",3);
        System.out.println(s1.getType());
        System.out.println(s1.calPerimeter());
        System.out.println(s2.getType());
        System.out.println(s2.calPerimeter());
    }
}

上面的main()方法中定義了兩個Shape類型的引用變量,它們分別指向Triangle對象和Circle對象。由於在Shape類中定義了calPerimeter()方法和getType()方法,所以程序可以直接調用s1變量和s2變量的calPerimeter()方法和getType()方法,無須強制類型轉換爲其子類類型。

利用抽象類和抽象方法的優勢,可以更好的發揮多態的優勢,使得程序更加靈活。

當使用abstract修飾類時,表明這個類只能被繼承;當使用abstract修飾方法時,表明這個方法必須由子類提供實現(即重寫)。而final修飾的類不能被繼承,final修飾的方法不能被重寫。因此final和abstract永遠不能同時使用。

注意:
abstract不能用於修飾成員變量,不能用於修飾局部變量,即沒有抽象變量、沒有抽象成員變量等說法;abstract也不能用於修飾構造器,沒有抽象構造器,抽象類裏定義的構造器只能是普通構造器。

除此之外,當使用static修飾一個方法時,表明這個方法屬於該類本身,即通過類就可以調用該方法,如果過該方法被定義成抽象方法,則將導致通過該類來調用該方法時出現錯誤(調用了一個沒有方法體的方法肯定會引起錯誤)。因此static和abstract不能同時修飾某個方法,即沒有所謂的類抽象方法。

注意:
static和abstract並不是絕對互斥的,static和abstract雖然不能同時修飾某個方法,但他們可以同時修飾內部類。

abstract關鍵字修飾的方法必須被其子類重寫纔有意義,否則這個方法將永遠不會有方法體,因此abstract方法不能被定義爲private訪問權限,即private和abstract不能同時修飾方法

發佈了101 篇原創文章 · 獲贊 139 · 訪問量 34萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章