2011-01-08 42 views
3

我正在學習java概念。 我對java繼承概念有了疑問。 在繼承中,我們可以將子類實例賦值給基類引用 ,並且我們只能訪問基類函數。 ,我們可以將繼承層次結構中的任何子類實例分配給基類引用。對於分配給特定基類引用的實例類型,我們只能訪問基類函數,並且我沒有發現任何差異。當我可以通過引用子類訪問所有方法時,爲什麼還要引用基類?

任何一個都可以給我實際的概念 爲什麼我們必須將子類實例分配給基類引用? 需要做什麼? 相反,我們可以從子類引用只知道這些基類函數。

通過考慮層次結構中的特定基類和許多子類來解釋。

回答

5

您可能想要這樣做的原因是爲了創建更強大的設計。以Java中的集合框架爲例。你有一個List接口,然後你有兩個實現,ArrayList和LinkedList。

你可以編寫程序來專門使用LinkedList或者ArrayList。但是,你的程序依賴於那些特定的實現。

如果您編寫程序以依賴超類型List,那麼您的程序可以用於任一List實現。比方說,你想寫一個做了一個列表的方法,你寫了這個:

public void doSomething(ArrayList a){} 

此方法只能用一個ArrayList,而不是一個LinkedList被調用。假設你想用LinkedList做同樣的事情?你會複製你的代碼嗎?

public void doSomething(List l){} 

將能夠接受任一類型的列表。

這背後的原理是程序接口而不是實現。也就是說,List定義了所有列表的功能。

這個用法有很多很多的例子。

1

Polymorphism

我是一種給你List<String>的方法。所有你需要知道的事情,我已經給你的東西是它是一個列表,並具有列表的行爲和語義,也就是說你可以把它放在裏面,它會保持它們的順序,你可以遍歷它。

你不需要知道的是我如何存儲的東西,我如何讓他們訪問等。這並不重要。對於你所關心的全部,它可能是一個LinkedList<String>,一個ArrayList<String>或者全新的東西。只要說一句,我已經選擇了一些東西,並且可以愉快地使用它。

當你使用繼承擴展類並添加新行爲時,你是絕對正確的,那麼你需要引用子類才能訪問它。這兩種方法有些互補,但不同的用例。

3

繼承性和多態性是面向對象編程的基石,服務幾個不同的目的,在短:

  • 碼通過擴展具有特定功能的基類重用
  • 接口設計通過提供一組抽象的功能,其中不同的實現根據不同的要求而定製並且
  • 封裝由隱藏特定功能,這在某些情況下不需要

等等。

最後一點也突出了爲什麼人們可能會使用一組受限制的功能,即使在實際實現提供的功能更多的情況下。以例如Collection接口爲例。通過使用此接口,我們專注於諸如isEmpty,containssize的方法,但不是實際的實現。

1

讓我們說車輛基地類和汽車平面子類。讓我們說Vehicle有一個方法move()。

汽車通過前進道路覆蓋此。飛機通過飛行覆蓋了這一點。

爲什麼move()應該是Vehicle基類的一部分?

因爲任何車輛都可以移動()。但是我們不能在Vehicle中實現move(),因爲所有的車輛不會以相同的方式移動,即沒有共同的行爲。我們仍然希望這個在基類中,以便我們可以有多態行爲,即我們可以編寫如下所示的代碼。正如你所看到的,只有一種叫做runVehicle(...)的方法可以用於任何Vehicle類。

void runVehicle(Vehicle v) 
{ 
    v.move(); 
} 

Car c=new Car(); 
runVehicle(c); 

Plane p=new Plane(); 
runPlane(p); 
2

你所描述的是多態性的本質。這是希臘語中的一個詞,意思是「多種形式」。

如果我給你一個簡單的層次結構這樣,你可以看到測試代碼如何能得到不同的計算實現了每個對象的不涉及自己什麼樣的形狀它處理的是:

public interface Shape 
{ 
    double calculateArea(); 
} 

class Circle implements Shape 
{ 
    private double radius; 

    Circle(double r) { this.radius = r; } 

    public double calculateArea() { return Math.PI*radius*radius; } 
} 

class Square implements Shape 
{ 
    private double side; 

    Square(double s) { this.side = s; } 

    public double calculateArea() { return side*side; } 
} 

// This would be a separate JUnit or TestNG annotated test. 
public class ShapeTest 
{ 
    @Test 
    public void testCalculateArea() 
    { 
     Map<Shape, Double> expected = new HashMap<Shape, Double>() 
     {{ 
      put(new Circle(1.0), Math.PI); 
      put(new Square(1.0), 1.0);    
     }}; 


     for (Shape shape : expected.keySet()) 
     { 
      Assert.assertEquals(expected.get(shape), shape.calculateArea()); 
     }  
    } 
} 
0

沒有真正的需要來做到這一點,除非API要求。例如,如果在一個特定的API或代碼庫是有

void ReallyUsefulFunction(BaseClass instance) 

,你想用,你可以派生類FOM的BaseClass並實現它的方法在子類中。然後,您現在可以將該子類傳遞給該函數。

不過,從技術上講,你可以實現自己的

void MyReallyUsefulFunction(MyClass instance) 

模仿相同的功能。但正如MYYM所解釋的那樣,代碼重用等的好處可能很大,那就是當你想要利用多態性時。

相關問題