[英]Why do we need abstract methods?
我最近一直在研究抽象方法,我不明白為什么我們需要它們? 我的意思是,畢竟,我們只是凌駕於它們之上。 你知道它只是一個聲明嗎? 我們為什么需要它們?
此外,我嘗試從互聯網上理解這一點,到處都有解釋,比如想象有一個抽象類人類,然后它的子類被禁用和未禁用,然后人類類walking()
的抽象函數將包含不同的主體或代碼。 現在我要說的是為什么我們不在禁用和未禁用的子類中創建一個函數而不是覆蓋。 因此再次回到第一段中的問題。 請解釋一下。
抽象方法最明顯的用途之一是讓抽象類從其他方法的實現中調用它們。
下面是一個例子:
class AbstractToy {
protected abstract String getName();
protected abstract String getSize();
public String getDescription() {
return "This is a really "+getSize()+" "+getName();
}
}
class ToyBear extends AbstractToy {
protected override String getName() { return "bear"; }
protected override String getSize() { return "big"; }
}
class ToyPenguin extends AbstractToy {
protected override String getName() { return "penguin"; }
protected override String getSize() { return "tiny"; }
}
請注意AbstractToy
的getDescription
實現如何能夠調用getName
和getSize
,即使定義在子類中。 這是一個著名的設計模式的實例,稱為Template Method 。
基類型中的抽象方法定義是一種契約,它保證該類型的每個具體實現都將具有該方法的實現。
沒有它,編譯器將不允許您在基類型的引用上調用該方法,因為它不能保證這樣的方法將始終存在。
所以如果你有
MyBaseClass x = getAnInstance();
x.doTheThing();
而MyBaseClass
沒有doTheThing
方法,那么編譯器會告訴你它不能讓你這樣做。 通過添加抽象doTheThing
方法,您可以保證getAnInstance()
可以返回的每個具體實現都有一個實現,這對編譯器來說已經足夠好了,因此它會讓您調用該方法。
基本上一個更基本的真理,首先需要了解的是:
您將有實例,其中變量的類型比它所保存的值的類型更通用。 在簡單的情況下,您可以使變量成為特定類型:
MyDerivedClassA a = new MyDerivcedClassA();
在這種情況下,您顯然可以調用MyDerivedClassA
任何方法,並且不需要基類中的任何抽象方法。
但有時你想對任何MyBaseClass
實例做一些事情,但你不知道它是什么特定類型:
public void doTheThingsForAll(Collection<? extends MyBaseClass> baseClassReferences) {
for (MyBaseClass myBaseReference : baseClassReferences) {
myBaseReference.doTheThing();
}
}
如果您的MyBaseClass
沒有doTheThing
抽象方法,那么編譯器不會讓您這樣做。
繼續你的例子,在某些時候你可能有一個人類列表,你並不真正關心他們是否被禁用,你關心的只是你想對他們調用 walk() 方法。 為了做到這一點,Human 類需要定義一個 walk() 方法。 但是,如果不知道人類是否殘疾,您可能不知道如何實施。 因此,您將實現留給繼承類。
在其他答案中有一些示例說明您如何使用它,所以讓我解釋一下您為什么要這樣做。
首先,面向對象設計的一個常見規則是,一般來說,您應該嘗試針對接口而不是特定實現進行編程。 如果您以后需要更改某些行為,這往往會提高程序的靈活性和可維護性。 例如,在我編寫的一個程序中,我們將數據寫入 CSV 文件。 我們后來決定改用寫入 Excel 文件。 對接口進行編程(而不是特定實現)使我們更容易進行此更改,因為我們可以“插入”一個新類來寫入 Excel 文件,而不是寫入 CSV 文件的類。
您可能還沒有研究過這個,但這對於某些設計模式來說實際上很重要。 工廠模式、策略模式和狀態模式是可能有用的一些值得注意的示例。
對於上下文,設計模式是描述和記錄已知問題的解決方案的標准方式。 例如,如果有人說“你應該使用策略模式來解決這個問題”,那么你應該如何處理這個問題的總體思路就清晰了。
因為有時我們需要一種在其實例中表現不同的方法。
例如,想象一個包含方法Shout
Animal
類。 我們將擁有此Animal
類的不同實例,但在某些情況下,我們需要以不同方式實現該方法,如下所示:
class Animal:
/**
different properties and methods
which are shared between all animals here
*/
...
method shout():
pass
class Dog extends Animal:
method shout():
makeDogVoice()
class Cat extends Animal:
method shout():
makeCatVoice()
dog = new Animal
cat = new Animal
dog.shout()
cat.shout()
所以狗叫得像狗,貓叫得像貓! 不執行兩次共享行為
在這些情況下,有不同的喊叫行為。 所以我們需要抽象類。
假設您不了解實現但仍想聲明一個方法,那么我們可以借助抽象修飾符來實現,並使其成為抽象方法。 對於抽象方法,只有聲明可用,而沒有實現。 因此它們應該以;
結尾;
例子:
public abstract void m1(); // this is correct
public abstract void m1(){ ... } // this is wrong
優點:通過在父類中聲明抽象方法,我們可以為子類提供指南,以便強制實現哪些方法。
例子:
abstract class Vehicle{
abstract int getNoOfWheels();
}
Class Bus extends Car{
public int getNoOfWheels(){
return 4;
}
}
如果你想要簡短的答案,想想這個:
你有一個抽象類Car
。
您實現了 2 個擴展它的類, Ferrari
和Mercedes
。
現在:如果您對所有汽車通用的方法drive()
執行以下操作之一會怎樣:
1)改變了方法的可見性,
2)將方法名稱從驅動更改為驅動,
3) 改變返回類型,從布爾值到整數
想想看。 它似乎沒有任何區別,因為它們是不同的實現?
錯誤的!
如果我遍歷汽車數組,我將不得不為每種類型的汽車調用不同的方法,從而使抽象的這種實現變得無用。
抽象類用於將具有公共模板的類分組,這些模板共享公共屬性。 這有幫助的一種方法是循環遍歷數組:抽象方法確保所有汽車聲明相同的方法,因此, Car
子類的任何對象都將具有方法drive()
,如抽象類中所定義,使for 循環提到易於實現。
希望這可以幫助。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.