CodeGym /Java Blog /Toto sisi /Java中抽像類的具體例子
John Squirrels
等級 41
San Francisco

Java中抽像類的具體例子

在 Toto sisi 群組發布
你好!在過去的課程中,我們遇到了接口並弄清楚了它們的用途。今天的話題與之前的話題相呼應。讓我們談談Java中的抽像類Java中抽像類的具體例子——1

為什麼類被稱為“抽象”

您可能還記得“抽象”是什麼——我們已經講過了。:) 如果您忘記了,請不要害怕。請記住:OOP 的一個原則是,在設計類和創建對象時,我們應該只識別實體的主要屬性並丟棄次要屬性。例如,如果我們正在設計一個SchoolTeacher類,我們幾乎不需要“高度”屬性。實際上,此屬性與教師無關。但是如果我們要創建一個BasketballPlayer類,那麼增長將是一個重要的特徵。所以聽著。一個抽像類就像它們來的一樣抽象——對於一組未來的課程來說,這是一個未完成的“空白”。空白不能按原樣使用。太“生”了。但它描述了繼承抽像類的未來類將擁有的某些狀態和一般行為。

抽象 Java 類的示例

考慮一個簡單的汽車示例:

public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public abstract void gas();

   public abstract void brake();

   public String getModel() {
       return model;
   }

   public void setModel(String model) {
       this.model = model;
   }

   public String getColor() {
       return color;
   }

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

   public int getMaxSpeed() {
       return maxSpeed;
   }

   public void setMaxSpeed(int maxSpeed) {
       this.maxSpeed = maxSpeed;
   }
}
這就是最簡單的抽像類的樣子。如您所見,它沒什麼特別的:) 為什麼我們需要它?首先,它以最抽象的方式描述了我們所需的實體,即汽車。我們使用抽像這個詞是有原因的。在現實世界中,沒有“抽象汽車”。有卡車、賽車、轎車、轎跑車和 SUV。 我們的抽像類只是一個“藍圖”,我們稍後將使用它來創建汽車類。

public class Sedan extends Car {

   @Override
   public void gas() {
       System.out.println("The sedan is accelerating!");
   }

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }

}
這與我們在繼承的課程中談到的非常相似。但是在那些課程中,我們有一個 Car 類,它的方法不是抽象的。但該解決方案有許多缺點,這些缺點已在抽像類中得到修復。首先,您不能創建抽像類的實例

public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Error! The Car class is abstract!
   }
}
Java 的創建者專門設計了這個“功能”。再次提醒:抽像類只是未來“普通”類的藍圖。你不需要藍圖的副本,對吧?而且您不會創建抽像類的實例 :) 但是如果類Car不是抽象的,我們可以輕鬆地創建它的實例:

public class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       // Some logic
   }

    public void brake() {
       // Some logic
   }
}


public class Main {

   public static void main(String[] args) {

       Car car = new Car(); // Everything is fine. A car is created.
   }
}
現在我們的程序有某種難以理解的汽車——它不是卡車,不是賽車,也不是轎車,而且完全不清楚它是什麼。這是自然界中不存在的非常“抽象的汽車”。我們可以使用動物提供相同的示例。想像一下如果Animal類(抽象動物)。目前還不清楚它是什麼動物,屬於什麼科,有什麼特徵。在您的程序中看到這一點會很奇怪。自然界中沒有“抽象動物”。只有狗、貓、狐狸、鼴鼠等。抽像類將我們從抽像對像中解放出來。它們為我們提供了基本的狀態和行為。例如,所有汽車都應該有modelcolormaximum speed,你應該能夠應用油門剎車。就是這樣。這是一個通用的抽象計劃。接下來你設計你需要的類。 注意:抽像類中的兩個方法也被指定為abstract,它們沒有任何實現。原因是一樣的:抽像類不會為抽象汽車創建默認行為。它們只是表明每輛車應該能夠做什麼。但是,如果確實需要默認行為,則可以在抽像類中實現方法。Java 不禁止這樣做:

public abstract class Car {

   private String model;
   private String color;
   private int maxSpeed;

   public void gas() {
       System.out.println("Gas!");
   }

   public abstract void brake();

   // Getters and setters
}


public class Sedan extends Car {

   @Override
   public void brake() {
       System.out.println("The sedan is slowing down!");
   }

}

public class Main {

   public static void main(String[] args) {

       Sedan sedan = new Sedan();
       sedan.gas();
   }
}
控制台輸出: “Gas!” 如您所見,我們在抽像類中實現了第一個方法,而不是第二個方法。因此,我們Sedan類的行為分為兩部分:如果調用該gas()方法,則調用'上升'到Car抽象父類,但是我們覆蓋了類brake()中的方法Sedan。這樣非常方便和靈活。但是現在我們的類不那麼抽象了?畢竟它的方法實現了一半。這個實際上是一個非常重要的特性——如果至少有一個方法是抽象的,那麼這個類就是抽象的. 兩種方法中的一種,或至少一千種方法中的一種——都沒有區別。我們甚至可以實現所有的方法,並且不保留任何抽象方法。那麼它就是一個沒有抽象方法的抽像類。原則上,這是可能的,編譯器不會產生錯誤,但最好避免它:抽像這個詞失去了意義,你的程序員同行們會很驚訝:/ 同時,如果一個方法被標記使用抽像一詞,每個子類都必須實現它或將其聲明為抽象。否則,編譯器將產生錯誤。 當然,每個類只能繼承一個抽像類,所以抽像類和普通類在繼承上沒有區別。不管我們繼承抽像類還是普通類,都只能有一個父類。

為什麼Java沒有類的多重繼承

我們已經說過 Java 沒有多重繼承,但我們還沒有真正探究為什麼。讓我們現在嘗試這樣做。事實上,如果 Java 具有多重繼承,子類將無法決定它們應該選擇哪種特定行為。假設我們有兩個類——ToasterNuclearBomb

public class Toaster {


 public void on() {

       System.out.println("The toaster is on. Toast is being prepared!");
   }

   public void off() {

       System.out.println("The toaster is off!");
   }
}


public class NuclearBomb {

   public void on() {

       System.out.println("Boom!");
   }
}
如您所見,兩者都有一個on()方法。對於烤麵包機,它開始烘烤。對於核彈來說,它會引發爆炸。哎呀:/現在想像一下你決定(不要問我為什麼!)在兩者之間創造一些東西。這樣你就有了一MysteriousDevice堂課! 當然,此代碼不起作用,我們僅將其作為示例提供,“但它可能是”:

public class MysteriousDevice extends Toaster, NuclearBomb {

   public static void main(String[] args) {

       MysteriousDevice mysteriousDevice = new MysteriousDevice();
       mysteriousDevice.on(); // So what should happen here? Do we get toast or a nuclear apocalypse?
   }
}
讓我們來看看我們有什麼。這個神秘裝置同時繼承了 Toaster 和 NuclearBomb。兩者都有on()方法。因此,如果我們調用該on()方法,則不清楚應該在對MysteriousDevice像上調用哪個方法。對像不可能知道。最重要的是:NuclearBomb 沒有off()方法,所以如果我們沒有猜對,就不可能禁用該設備。 Java中抽像類的具體例子——2正是由於這種“混亂”,對像不知道該表現出什麼行為,Java 的創建者才放棄了多重繼承。但是,您會記得 Java 類可以實現多個接口。 順便說一句,在您的學習中,您已經至少遇到過一個抽像類!

public abstract class Calendar implements Serializable, Cloneable, Comparable<Calendar>
這是你的老朋友,班級Calendar。它是抽象的,有幾個孩子。其中之一是GregorianCalendar。您已經在有關日期的課程中使用過它。:) 一切似乎都很清楚。只有一個問題:抽像類和接口之間的根本區別到底是什麼?為什麼他們將兩者都添加到 Java 而不是將語言限制為一種?畢竟,那已經完全足夠了。我們將在下一課討論這個!直到那時 :)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION