2012-08-01 124 views
3

,同時爲了減少在我的項目的代碼複製推廣一些類我有一個錯誤,情況如下:Java泛型和多態性

interface ClassRoot{} 

public class ClassChild1 implements ClassRoot{ 
    // constructor is omitted for simplicity 
    public Collection<ClassChild1> createList(){ 

     Collection<ClassChild1> col = getCollectionFromSomewhere(); 
     return col; 
    } 
} 

public class Class1{ 
    protected <T extends ClassRoot> Collection<T> doSth(){ 
     Collection<T> myCol = null; 
     ClassChild1 child = new ClassChild1(); 

     // here I get compile time assignment error 
     // also (assuming that myCol not null) myCol.add(new ClassChild1()); 
     // is not permitted. 
     myCol = child.createList(); 
     return myCol; 
    } 
} 

是不是對多態現象?我知道,例如,

List<Object> list1; 

永遠不能(也不應該被指定爲類型安全)到:

List<String> list2; 

但在這裏我的情況是不同的,我指定的類型參數擴展一些特定的類希望利用OOP多態概念,做好正確實施正確課程的作業。 現在我有2個問題;

  • 有人可以清楚地解釋爲什麼這是禁止在Java中,爲什麼有正當理由?
  • 如何通過使用類型參數或通配符來實現這樣的功能?
+1

createList()應返回Collection 而不是ClassChild1。你沒有編譯錯誤嗎? 爲了清楚起見,您應該在您的問題中解釋您的錯誤,而不僅僅是代碼註釋。 – kgautron 2012-08-01 08:47:20

+0

編輯爲公開收藏 createList()。 – px5x2 2012-08-01 10:12:03

回答

1

的分配,因爲你是一個未知類型T,這可能會或可能不會ClassChild1分配Collection<ClassChild1>Collection參數

Collection<T> myCol = null; 
myCol = child.createList(); 

將失敗。

您已指定T如在調用點推斷,所以想象下面的代碼:

Class1 c1; 
Collection<ClassChild2> c = c1.doSth(); 

你可以看到,編譯器會畫自己到一個角落裏,如果它允許你編譯這樣的doSth方法因爲在該方法內部,您想要將一個ClassChild1實例添加到在此示例中恰好存放ClassChild2的實例的集合中。

+0

Ups,我編輯了錯誤的部分,現在你會看到 – px5x2 2012-08-01 10:11:37

+0

感謝Marco,給出瞭解釋.. – px5x2 2012-08-01 11:48:20

0
Collection<ClassChild1> col = getCollectionFromSomewhere(); 
return col; 

正在返回一個集合,但實際上你的ClassChild1不是一個集合。這肯定會造成編譯時錯誤。確保該方法的返回類型必須是集合類型或其後代

0

createList不提供集合,這也是一個錯誤。

您不能將ClassChild1的列表分配到T的列表中。

例如,如果您將RootClass重命名爲Animal,ClassChild1Cat。如果現在有一個T的實例不是Cat,那麼顯然你不能完成你想要的任務。

0

這很難說是什麼問題,因爲:

public ClassChild1 createList(){ 

一定是錯誤的(正如其他人指出的)。其實是否說:

public Collection<ClassChild1> createList(){ 

這將編譯好的:

import java.util.*; 

interface ClassRoot {} 

class ClassChild1 implements ClassRoot { 

    public Collection<? extends ClassRoot> createList(){ 

     Collection<ClassChild1> col = new ArrayList<ClassChild1>(); 
     return col; 
    } 
} 

class Class1{ 
    protected Collection<? extends ClassRoot> doSth(){ 
     Collection<? extends ClassRoot> myCol = null; 
     ClassChild1 child = new ClassChild1(); 

     myCol = child.createList(); 
     return myCol; 
    } 
} 

我已經聲明createList返回的東西是分配給ClassRoot。它返回的是與之兼容的。

然後我改變了doSth返回相同的東西,所以它也兼容。

的缺點是,你仍然無法撥打:

myCol.add(child); 

而對於一個很好的理由 - 儘管我們不知道的藏品存在什麼限制,這並不意味着不存在限制(當您關閉燈光時,房間不會消失)。

0

在這裏考慮你的代碼。你ClassChild實現,

public class ClassChild implements ClassRoot { 
    public List<ClassChild> createList() { 
     return Arrays.asList(new ClassChild[] {new ClassChild(), new ClassChild()}); 
    } 


} 

和你的Class1的是

public class Class1 { 

    public static <T extends ClassRoot> Collection<T> doSth(){ 
     Collection<T> myCol = null; 
     ClassChild child = new ClassChild(); 
     /*you should note here*/ 
     myCol = (Collection<T>) child.createList(); 
     return myCol; 
    } 
} 

你必須停止,並在那裏我已經提到的「你一定要注意這裏的」地方。如果您將劇集製作爲收藏集,則問題已解決。但是就你的問題而言,你已經創建了一個名爲myCol的集合,其中包含擴展ClassRoot的T類型。但是,保證createList將返回包含子類ClassRoot的集合是什麼?所以你總是明確地施放。