1. 程式人生 > >Java之抽象類與抽象方法

Java之抽象類與抽象方法

目錄

  • Java之抽象類與抽象方法
    • 抽象概念
    • 抽象類與方法
    • 注意事項

Java之抽象類與抽象方法

抽象概念

本篇關鍵詞是抽象,那麼何為抽象?百度百科告訴我們,抽象就是概括具體事務共同的方面、本質屬性等,而將個別的方面、屬性等捨棄的思維過程。在Java裡,也就是把各個具體的類中共有的方法提取出來,放到基類之中,而基類並不需要了解子類中該方法具體是怎麼實現的,這個基類就是所謂的抽象類,這些不需要知道具體實現方式的方法就是抽象方法。

抽象類體現模板模式的設計,抽象類作為多個子類的通用模板,子類在抽象類的基礎上進行擴充套件、改造,但子類總體上會大致保留抽象類的行為方式。

抽象類與方法

讓我們結合程式碼,好好地分析一波:

package com.my.pac18;

/**
 * @auther Summerday
 */
/*抽象是很有用的重構工具,能夠讓共有的方法沿著繼承層次向上移動。*/
public abstract class Shape {
    //抽象類中的初始化塊
    {
        System.out.println("Shape.instance initializer");
    }
    //抽象類中的例項變數
    private String color;
    //抽象類中可以有靜態方法及屬性。
    public static String name="形狀";
    public static void output(){
        System.out.println("父類的static方法");
    }
    //計算周長,但是並不知道具體細節的抽象方法
    public abstract double calPerimeter();
    //返回形狀的抽象方法

    //[修飾符] abstract 返回型別 方法名();
    public abstract String getType();
    //抽象類中的構造器,用於被繼承
    public Shape() {
    }

    public Shape(String color) {
        System.out.println("Shape.Shape");
        this.color = color;
    }
    //抽象類中的普通例項方法
    public String getColor() {
        return color;
    }
}

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;
    }

    @Override
    public double calPerimeter() {
        return 2 * Math.PI * radius;
    }

    @Override
    public String getType() {
        return getColor() + "圓形";
    }

    //如果從一個抽象類繼承,並建立該新類的物件,就必須給基類的所有抽象方法提供定義。
    public static void main(String[] args) {
        Shape.output();
        //Shape是抽象類,不能建立Shape類的物件
        //但是可以讓Shape類的引用變數指向其子類的物件
        Shape[] shapes = new Shape[]{new Circle("紅色", 5), new Rectangle("綠色", 6, 6)};
        for (Shape p : shapes) {
            
            System.out.println(p.getType() + "的周長為" + p.calPerimeter());
        }

    }
}

class Rectangle extends Shape {
    
    private double length;
    private double width;

    public Rectangle() {
        System.out.println("父類的構造器不是為了建立物件,而是供給子類繼承的");
    }

    public Rectangle(String color, double length, double width) {
        super(color);
        this.length = length;
        this.width = width;
    }

    public boolean isSquare() {
        return length == width;
    }

    public double calPerimeter() {
        return (length + width) * 2;
    }

    public String getType() {
        if (isSquare()) return getColor() + "正方形";
        return getColor() + "長方形";
    }
}

//測試結果
父類的static方法
Shape.instance initializer
Shape.Shape
Shape.instance initializer
Shape.Shape
紅色圓形的周長為31.41592653589793
綠色正方形的周長為24.0

順著上面的例子,我們簡單地分析一下,抽象類與抽象方法到底是啥?又需要注意些啥?

  • 首先定義了一個抽象類:Shape類。可以看到,抽象類由abstract關鍵字修飾。
//[修飾符] abstract class 類名
public abstract class Shape
  • 然後再Shape類裡定義了兩個抽象方法(方法可以被重寫,屬性不可以,抽象是針對方法而言的):getType()calPerimeter()可以看出抽象方法宣告時並沒有定義方法體,因為基類中並不需要知道具體的實現方式是怎樣,只要知道有這個方法就可以了。你建立一個圓形例項,具體如何算圓形的周長,在圓形類給出抽象方法的定義即可。
//[修飾符] abstract 返回型別 方法名();
 public abstract double calPerimeter();
 public abstract String getType();

注意事項

  • 如果子類從抽象父類繼承而來,那麼子類就必須重寫父類的抽象方法,給出方法的具體實現形式。你的爸爸說你會算周長,你總得告訴大家周長怎麼算吧。但是,如果子類中也重寫父類的方法也宣告為抽象的話,這時父類方法在子類中的實現也無效了。就好比,你說你也不知道怎麼算周長,隔壁小王才是真的會。
@Override
public double calPerimeter() {
    return 2 * Math.PI * radius;
}
@Override
public String getType() {
    return getColor() + "圓形";
}
  • 抽象類不能例項化,不能用new來呼叫抽象類構造器建立抽象類的例項。可以想象,既然是抽象的,建立它的例項就沒多大意義,建立具體實現的子類的例項才能解決問題。
  • 抽象類可以用作一種資料型別,可以讓抽象類的引用變數指向它的子類物件,很好理解,不這樣的話,抽象帶來的好處體現在哪呢。通過抽象類的引用變數呼叫抽象類中的方法,就能夠根據動態繫結,在執行時根據引用物件的實際型別執行抽象方法的具體表現形式。
  • 抽象類中是能夠有具體實現的成員方法(例項方法和類方法),以及明確的成員屬性(例項屬性和類屬性)。
//抽象類中的例項方法,子類繼承使用。
public String getColor() {
        return color;
    }
//抽象類中可以有靜態方法和屬性,類名.方法(屬性)呼叫。
public static String name="形狀";
public static void output(){
    System.out.println("父類的static方法");
}
  • 抽象類中還可以有構造器,但是僅僅是為了供給子類繼承使用,因為上面講過,抽象類無法建立例項物件!!!(重點回顧:子類無法繼承父類構造器,只是單純呼叫父類構造器的初始化程式碼,繼承和呼叫是不一樣的!!!
//子類
public Shape() {
    }

public Shape(String color) {
    System.out.println("Shape.Shape");
    this.color = color;
}
  • 抽象類中還有程式碼塊和內部類,關於內部類之後將會學習,暫時就不舉例了。
 //抽象類中的初始化塊
{
    System.out.println("Shape.instance initializer");
}
  • 一個類中如果有抽象方法,那麼這個類也一定是抽象的。畢竟你的方法定義尚且都不完全,建立你的例項又有啥用呢。但是一個抽象類中可以沒有抽象方法,只是單純不讓人建立它的例項物件。

  • 子類是抽象,父類也可以是具體的。如上,Object類是所有類的超類,它是具體的,我們定義的Shape類是可以抽象的。

  • 抽象是實現多型的一種機制,那麼不具備多型性的,就不能稱之為多型。諸如private、static、final修飾的方法或構造器屬於靜態繫結,不具備多型性,不能作為抽象的修飾。

本文是根據資料以及個人測試之後所得,若有錯誤或者理解不當之處,還望評論區指出,謝