2011-03-18 102 views
22

我有一個抽象類,它有一個泛型的方法,我想通過將泛型參數替換爲特定類型來覆蓋泛型方法。所以在僞代碼我有以下幾點:Java的泛型方法的繼承和覆蓋規則

public abstract class GetAndParse { 
    public SomeClass var; 

    public abstract <T extends AnotherClass> void getAndParse(T... args); 
} 

public class Implementor extends GetAndParse { 
    // some field declarations 

    // some method declarations 

    @Override 
    public <SpecificClass> void getAndParse(SpecificClass... args) { 
    // method body making use of args 
    } 
} 

但由於某種原因,我不能這樣做?我是否犯了某種語法錯誤,或者這種繼承和覆蓋是不允許的?具體來說,我得到一個關於@Override的錯誤,因爲eclipse IDE不停地提醒我執行getAndParse

下面是我希望上面的代碼工作。在我的代碼中的其他地方,有一種方法需要實現GetAndParse的對象實例,這意味着它們具有我可以使用的getAndParse方法。當我打電話getAndParse該實例上編譯器檢查,看看我是否在正確的方式使用的T具體實例,所以特別T應該擴展AnotherClass,它應該是SpecificClass

+0

僞代碼太抽象,需要更多信息 – irreputable 2011-03-18 00:48:48

+0

使用'public abstract void getAndParse(Args ... args);'沒有任何意義。什麼是類型參數適合?編譯器應該如何確定它的實際值以及它在哪裏使用它? – maaartinus 2011-03-18 00:50:19

+0

你能給我們一個完整的例子,它實際上是可編譯的(除了有問題的錯誤),併產生你提到的錯誤? – 2011-03-18 01:47:24

回答

23

我們有這裏什麼是兩種不同的方法,每個單獨的類型參數。

public abstract <T extends AnotherClass> void getAndParse(Args... args); 

這是與名爲T A型參數的方法,以及通過AnotherClass界,意思的AnotherClass各亞型被允許作爲類型參數。

public <SpecificClass> void getAndParse(Args... args) 

這是與名爲SpecificClass類型參數,通過Object界(這意味着每個類型被允許作爲類型參數)的方法。你真的想要這個嗎?

是否在Args內部使用了類型參數?我認爲問題會在那裏。


編輯:

public abstract <T extends AnotherClass> void getAndParse(T... args); 

的意思是,該方法的呼叫者可他想調用的方法哪種類型的參數決定的,只要這是某些子類型爲AnotherClass。這意味着實際上可以用AnotherClass類型的任何對象調用該方法。

由於調用者可以決定類型參數,因此不能在子類中將參數類型限制爲SpecificClass - 這不是該方法的實現,而是另一個具有相同名稱(重載)的方法。

也許你想是這樣的:

public abstract class GetAndParse<T extends AnotherClass> { 
    public SomeClass var; 

    public abstract void getAndParse(T... args); 
} 

public class Implementor extends GetAndParse<SpecificClass> { 
    // some field declarations 

    // some method declarations 

    @Override 
    public void getAndParse(SpecificClass... args) { 
    // method body making use of args 
    } 
} 

現在getAndParse方法實現父類的方法。

+3

我不想要一個類型參數。我希望編譯器檢查並確保'SpecificClass'是'AnotherClass'的擴展。 – davidk01 2011-03-18 03:41:38

1

不,它是無效的。如果某個參與GetAndParse的人將其稱爲的其他類延伸AnotherClass,會發生什麼情況?

+0

我不明白爲什麼這是一個問題。我有一個擴展'GetAndParse'並將'T'的類型修正爲'SpecficClass',編譯器檢查以確保當我有一個'Implementor'實例並調用'getAndParse'時,在我的代碼中擴展'AnotherClass'。與不匹配'SpecificClass'的類型,我應該得到一個錯誤。 – davidk01 2011-03-18 01:43:58

+0

@ davidk01:由GetAndParse提供的合同表示每個實現它的人都必須爲任何擴展AnotherClass的類型這樣做。給定'GetAndParse foo = new Implementor();'你必須能夠調用'foo.getAndParse'作爲AnotherClass的任何擴展 - 如果編譯器沒有強制執行這個,你可以使用Object,泛型的意義在於確保編譯時安全類型 – Erik 2011-03-18 08:28:34

1

當某人有一個引用類型GetAndParse並嘗試調用getAndParse方法時,這變成了無稽之談。如果貓和狗延長AnotherClass。我希望能夠用Cat或Dog來調用GetAndParse#getAndParse。但是實現已經試圖限制它,並使其不兼容!

+0

這就是你想要做的事情是不可能的原因,如果我以一種你不喜歡的方式來構建它,我表示歉意。編譯時間泛型不能爲您執行。編譯器如何知道運行時會出現哪些子類?實現者完全有可能通過工廠界面返回,並且來自不同的庫,您甚至不會編譯它們!在編譯時無法檢查類型參數的縮小情況以確保安全。 – Affe 2011-03-18 04:17:08

8

由於Java泛型中的「擦除」這個概念,你會看到這個問題。 Java使用「擦除」來支持向後兼容性。即不使用泛型的Java代碼。

擦除過程:
編譯器將首先做一個類型檢查,然後它會刪除(清除)所有類型參數儘可能,還插入鑄字在以往任何時候必要的。

例如:

public abstract <T extends AnotherClass> void getAndParse(T paramAnotherClass); 

將變得

public abstract void getAndParse(AnotherClass paramAnotherClass); 

在類 「Implementor.java」,

代碼

public <SpecificClass> void getAndParse(T paramAnotherClass) 

將變得

public void getAndParse(SpecificClass paramAnotherClass){ } 

編譯器會看到你沒有正確實現抽象方法。 抽象方法和實現的方法之間存在類型不匹配。這就是你看到錯誤的原因。

更多細節可以在這裏找到。 http://today.java.net/pub/a/today/2003/12/02/explorations.html

1

你不能覆蓋特定類型T,因爲在實際上(在字節碼級,如果你願意的話),因爲類型擦除(見其他答案)的只有一個方法getAndParse:

public abstract void getAndParse(AnotherClass... args); // (1) 

每T的類型,使用相同的方法。

可以超載它(我認爲):

但這不會從一個不同的方法(1)螞蟻會被通用代碼調用:

T x = whatever; 
    object.getAndParse(x); // Calls (1) even if T is derived from SpecificClass