2010-01-14 127 views
5

看看這三個類。 Minatchi允許自己擴展,以便其方法的返回類型也可以擴展。爲了說明,我使用了一種靜態方法。Java泛型擴展返回類型的方法

public class Minatchi<T extends Minatchi<?>>{ 

    static public <T extends Minatchi<?>> 
    List<T> listAll(){ 
     return 
     (List<T>) query(); 
    } 
} 

於是我繼承Minatchi到夫人

public class Lady 
extends Minatchi<Lady>{ 

} 

這是可疑的行爲發生。

public class HelloMinatchi{ 

    private void listA(){ 
    List<Lady> uvs = Lady.listAll(); 
    for (Lady uv: uvs){ 
     logger.info(uv.getName()); 
    } 
    } 

    private void listB(){ 
    for (Lady uv: Lady.listAll()){ 
     logger.info(uv.getName()); 
    } 
    } 
} 

方法listA和listB基本相同。 listA將列表放入中間變量uvs, 而列表B直接將listAll放入for-loop標頭。

但是,對於listB,編譯器抱怨無法將Minatchi <?>轉換爲Lady。

所以這個問題是關於Java泛型的設計完整性。還有另一種泛型抱怨。

這是一個故意的設計功能還是Java通用設計人員不知道如何解決的無意設計錯誤。如果有意爲之,他們爲什麼這樣做?如果有錯誤,他們是否打算解決它?

或者這是我個人的問題,我不知道更好的方式來聲明泛型?如果是這樣,告訴我如何。

(我使用的通用Minatchi類,因爲我已非靜態方法暴露於類擴展過,這是我在這個問題排除在外。)

+0

我使用了一個通用的Minatchi類,因爲我有非靜態方法也暴露給類擴展,我忽略了題。 – 2010-01-14 13:17:07

回答

5

靜態方法不接受類中的泛型類型定義。即listAll()方法不知道Lady(在extends Minatchi<Lady>中)。

它的返回類型由表達式的左側推斷:

  • listA()左手側限定,它預計List<Lady>
  • listB() foreach循環看起來也應該期望Lady,但似乎編譯器沒有正確指示forEach循環。

使listB()工作的方式是告訴它使用的泛型類型:

for (Lady uv : Lady.<Lady>listAll()) {..} 
+0

感謝bozho。我在吸菸什麼? – 2010-01-14 12:57:14

1

你的問題是,你讓編譯器推斷通用參數給listAll方法,在第一種情況下,它推斷出你想要的,因爲你將結果存儲在一個變量中,並且它只能查看變量的類型。在第二它不能自動推斷出「正確」的類型,所以你需要自己指定:

for (Lady uv: Lady.<Lady>listAll()){ 
    logger.info(uv.getName()); 
} 

請注意,在這個例子中,我們沒有理由對Minatchi類是通用爲不完全影響靜態方法。

請注意,調用Lady.listAll與調用Minatchi.listAll完全相同(即,它不影響編譯器可以或將推斷爲通用參數的類型)。

+0

女士。 listAll(),而不是Lady.listAll ();)(更正它爲你) – Bozho 2010-01-14 12:49:14

+0

如果編譯器可以從一個變量推斷,它肯定應該沒有問題推斷從for循環頭變量的類型。 for(Lady uv:Lady.listAll()) 這個問題不是關於如果我應該使用中間變量。相反,這是爲什麼語言設計者忘記了容納for循環?爲什麼他/他們不能使用for循環變量? IOW,他們在吸菸? – 2010-01-14 12:53:00

+0

謝謝。我應該在發佈之前進行測試。 – sepp2k 2010-01-14 12:53:16

1

這是由於類型擦除而發生的。

Java Generic tutorial

當一般類型被實例化, 編譯器通過 翻譯這些類型的技術稱爲類型擦除 - 一個 方法,其中,編譯器將刪除輸入參數 相關所有 信息和在類中輸入參數或 方法。

,因爲呼叫Lady.ListAll的原始類型Minatchi執行時,編譯器無法知道具體的類型是Minatchi使用

類型消除仿製藥,使泛型類型是兼容在將泛型添加到庫之前編譯Java庫。已經有一些努力來擁有reification added to Java,但它並不在Java 7的路線圖中。

+0

真的嗎?我認爲類型擦除只發生在運行時。這個錯誤出現在編譯時。 – nanda 2010-01-14 12:53:36

+0

@nanda:類型擦除處於編譯時 - 如果類型在運行時已知,則不需要擦除它。 – 2010-01-14 12:54:51

+0

我的意思是,刪除是在編譯時,所以運行時不知道泛型類型,但是在編譯類之前出現錯誤檢查。如果它有錯誤,它如何被編譯? – nanda 2010-01-14 12:58:40