2013-06-25 60 views
13

這可能以前曾經有過一百萬次的問題,但我無法在包裝類型參數的抽象類上編寫一個複製構造函數。我有一些代碼,看起來像這樣:使用泛型的Java複製構造函數

public abstract class Superclass<T> { 
    Set<? extends Variable<T>> vars; 

    public abstract Superclass<? extends T> copy(); 

    class Variable<T> { 
     T value; 
    } 
} 

class Foo extends Superclass<Integer> { 
    public Foo copy() { 
     Foo _newFoo = Foo(); 
     Set<FooVariable> _newVars = new HashSet<FooVariable>(); 
     _newVars.addAll(this.vars); 
     _newFoo.vars = _newVars; 
    } 

    class FooVariable extends Variable<Integer> { /* ... */ } 
} 

class Bar extends Superclass<String> { 
    public Bar copy() { 
     Bar _newBar = Bar(); 
     Set<BarVariable> _newVars = new HashSet<BarVariable>(); 
     _newVars.addAll(this.vars); 
     _newBar.vars = _newVars; 
    } 

    class BarVariable extends Variable<String> { /* ... */ } 
} 

由於兩個FooBarcopy方法是除了變量類型相同,我希望能夠在該代碼轉移到具體的方法超類。但我想不出(一)如何有具體的public Superclass<? extends T> copy方法返回一個Foo例如,如果叫上FooBar例如,如果叫上Bar和(b)填充vars鑲有FooVariable S或BarVariable S作爲適當。

任何人都可以請幫忙告訴我我錯過了什麼嗎?謝謝。

+2

複製構造函數是一個實際的構造函數,它接受該類的一個實例作爲參數。這更像是一種複製方法。 –

+0

不會給這些'Foo _newFoo = Foo();'編譯錯誤,那麼缺少的返回類型呢?或者我完全誤讀了一些概念 – exexzian

回答

0

引入第二個泛型類型參數來表示Variable<T>U

然後,Foo.FooVariable<T>Bar.BarVariable<T>滿足U的界限,並且可以從copy方法返回。

編輯

我已經改變了代碼的copy實施搬進超。它依賴於newInstance方法(@OndrejBozek已經介紹過)。

public abstract class Superclass<T, U extends Variable<T>> { 
    Set<U> vars; 

    class Variable<T> { 
     T value; 
    } 

    public Superclass<T, U> copy() { 
     Superclass<T, U> _newSuperclass = newInstance(); 
     Set<U> _newVars = new HashSet<U>(); 
     _newVars.addAll(vars); 
     _newSuperclass.vars = _newVars; 
     return _newSuperclass; 
    } 

    public abstract Superclass<T, U> newInstance(); 
} 

class Foo extends Superclass<Integer, Foo.FooVariable> { 
    public Foo newInstance() { return new Foo(); } 

    class FooVariable extends Variable<Integer> { /* ... */ } 
} 

class Bar extends Superclass<String, Bar.BarVariable> { 
    public Bar newInstance() { return new Bar(); } 

    class BarVariable extends Variable<String> { /* ... */ } 
} 
+0

感謝您的幫助。儘管這個解決方案確實強制了我感興趣的類型安全性,但我仍然在'Foo.copy'和'Bar.copy'方法中重複了代碼。你能想到一種將所有代碼移入超類的方法嗎? – jay

+0

@jay,我修改了我的答案,試圖將'copy'移入超類。 – rgettman

2

這種Superclass怎麼辦?

public abstract class Superclass<T> { 

    Set<? extends Variable<T>> vars; 

    public Superclass<? extends T> copy() { 
     Superclass<T> _newSuperclass = this.getNewInstance(); 
     Set<Variable<T>> _newVars = new HashSet<Variable<T>>(); 
     _newVars.addAll(this.vars); 
     _newSuperclass.vars = _newVars; 
     return _newSuperclass; 
    } 

    public abstract Superclass<T> getNewInstance(); 

    class Variable<T> { 

     T value; 
    } 
} 

的一點是,你只需要在子類的構造函數,而不是實行getNewInstance()

所以Foo看起來就像:

class Foo extends Superclass<Integer> { 

    @Override 
    public Superclass<Integer> getNewInstance() { 
     return new Foo(); 
    } 

    class FooVariable extends Variable<Integer> { /* ... */ } 
} 
+0

是的,它編譯。用Java 1.7編譯它。該代碼應該是什麼錯誤? –

+1

對不起,我想錯了... – jlordo

+0

我認爲你缺少'_newSuperClass.vars = _newVars;' – Alex

0

測試此代碼,它有一些警告,但你想要做什麼:

public <C extends Superclass<? extends T>> C copy() throws InstantiationException, IllegalAccessException { 
    C result= (C) this.getClass().newInstance(); 
    HashSet newVars= new HashSet(); 
    newVars.addAll(this.vars); 
    result.vars= newVars; 
    return result; 
} 

一個備註:這是不是複製構造函數。這只是一種複製方法。構造函數沒有返回類型,其名稱等於類名稱。