2010-12-17 130 views
1

我有一個父類Builder可與Builder類型或其子類型的參數泛型:泛型類和繼承問題

class Builder<T extends Builder> { 

    @SuppressWarnings("unchecked") 
    T doSmth() { 
     System.out.println("do smth"); 
     return (T)this; 
    } 
} 

它有一個子類 - BuilderChild

class BuilderChild extends Builder<BuilderChild> { 

    BuilderChild doSmthElse() { 
     System.out.println("do smth else"); 
     return this; 
    } 
} 

所以,我可以在BuilderChild實例上調用方法doSmth並返回BuilderChild

new BuilderChild().doSmth().doSmthElse(); 

但是,當我試圖generify BuilderChild上面的行停止編譯。

class BuilderChild<T> extends Builder<BuilderChild> { 

    BuilderChild doSmthElse() { 
     System.out.println("do smth else"); 
     return this; 
    } 
} 
... 
//Compile error, because doSmth() 
//returns Builder instead of BuilderChild. 
new BuilderChild().doSmth().doSmthElse(); 

有人能解釋爲什麼doSmth()開始返回Builder我泛型BuilderChild後?有什麼方法可以解決它嗎?

回答

5

問題是,您正在使用BuilderChild作爲原始類型。

這意味着它具有類型參數,但是您在不提供任何類型參數的情況下指定它。

這意味着幾乎所有該類型的泛型信息都將被忽略(它是a bit more complicated than that,但這是高級視圖)。

如果你寫的這個:

new BuilderChild<Object>().doSmth().doSmthElse(); 

然後再編譯。另外,doSmthElse應指定爲BuilderChild<T> doSmthElse()

請注意,原始類型僅支持向後兼容性,不應在新代碼中使用。

0

我建議做這樣的事情:

abstract class Builder<T extends Builder> { 

    protected T getThis(); 

    @SuppressWarnings("unchecked") 
    T doSmth() { 
     System.out.println("do smth"); 
     return getThis(); 
    } 
} 

class BuilderChild extends Builder<BuilderChild> { 
    protected T getThis() { return this; } 
    [...] 

雖然客戶端代碼可能是最好讓建設者非通用。