2013-06-25 20 views
13

これはおそらく何百万回も前に尋ねられていますが、バインドされた型パラメータを持つ抽象クラスにコピーコンストラクタを書き込むのは難しいです。 FooBarの両方のためのcopy方法は、変数の型を除いて同じであるので、私は具体的な方法にそのコードを移動できるようにしたいのですが、ジェネリックの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> { /* ... */ } 
} 

:私はこのようになりますいくつかのコードを持っていますスーパークラス。しかし、私は、(a)はFooBarインスタンスで呼び出された場合Barに呼び出された場合、具体的なpublic Superclass<? extends T> copy方法はFooインスタンスを返すようにする方法と、(b)FooVariable SまたはBarVariableのようにvarsセットに移入を把握することはできません適切な。

誰かが助けてくれて、私に何が欠けているか教えてください。ありがとう。

+2

コピーコンストラクタは、クラスのインスタンスを引数として受け入れる実際のコンストラクタです。これはもっとコピー方法です。 –

+0

これは 'Foo _newFoo = Foo();'でコンパイルエラーが発生し、欠落している戻り値の型はどうですか?または私はいくつかの概念を完全に誤解しています – exexzian

答えて

0

Variable<T>,Uを表す第2ジェネリック型パラメータを導入します。

次に、Foo.FooVariable<T>およびBar.BarVariable<T>は、Uの範囲を満たし、copyメソッドから返すことができます。

EDIT

私はスーパーへ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; 
} 

は一つの発言:これではありませんコピーコンストラクタ。これはほんのコピー方法です。コンストラクターには戻り値の型がなく、その名前はクラス名と同じです。