2009-03-26 3 views
1

抽象コレクションクラス(空間と呼ばれる)と 抽象要素クラス(Atomと呼ばれます)を作成したいと思います。両方のインスタンスはお互いを知る必要があります(正確に型指定されている)。 それは問題です。Javaの汎用クラス(型安全)は、お互いに依存します

abstract class Space<A extends Atom>{ 
    // ... 
} 

abstract class Atom<S extends Space>{ 
    // ... 
} 

は良くない:

"Aがアトムを拡張するには、" 任意の原子を意味ではなく、強く1

は "Sはスペースを拡張し、" 入力した任意の空間を意味ではなく、強く型付けされた1

abstract class Space<A extends Atom<? extends Space>> 
abstract class Atom<S extends Space<? extends Atom>> 

abstract class Space<S, A extends Atom<S extends Space<A>>> 
abstract class Atom<A, S extends Space<A extends Atom<S>>> 

and so on ... 

:私は、次の試行のいずれかで、完全な型の安全性に到達することはできません

これら2つのクラスは抽象クラスであり、2つのサブクラスが互いに型付けされていることを覚えておきたい。 、次の例 のクラスのSomeSpaceとSomeAtomが互いの強い「タイプの知識」を持っていなければならないことを意味

class SomeSpace extends Space<SomeAtom> 
class SomeAtom extends Atom<SomeSpace> 
+0

いいえ私は噛んでいます。なぜあなたはこれをやっていますか? :)これはあなたの実際の抽象的なですか、それとも質問の単なる例ですか? – cletus

+1

実際のコード例のための私自身の '答え'を参照してください –

答えて

4

これは私にはうってつけですが、私はこれらの一般的な制約について本当に混乱しました。つまり、それができることを保証するものではありません:

interface ISpace<S extends ISpace<S, A>, A extends IAtom<S, A>> { 
     List<? extends IAtom<S, A>> getList(); //// CHANGED 
} 

interface IAtom<S extends ISpace<S, A>, A extends IAtom<S, A>> { 
     S getSpace(); 
} 

abstract class Space<S extends Space<S, A>, A extends Atom<S, A>> 
       implements ISpace<S, A> { 

     private final List<Atom<S, A>> atoms = new LinkedList<Atom<S, A>>(); ////CHANGED 

     public Space() { 
     } 
     public Space<S, A> getSpace() { 
       return this; 
     } 
     @Override 
     public List<Atom<S, A>> getList() { //// CHANGED 
       return atoms; 
     } 
} 

abstract class Atom<S extends Space<S, A>, A extends Atom<S, A>> 
       implements IAtom<S, A> { 

     private final S space; 

     public Atom(S someSpace) { 
       this.space = someSpace; 
       space.getList().add(this); 
     } 

     @Override 
     public S getSpace() { 
       return space; 
     } 

     public Atom<S, A> getAtom() { 
       return this; 
     } 
} 

class Space1 extends Space<Space1, Atom1> { 
     public Space1() { 
     } 
} 

class Atom1 extends Atom<Space1, Atom1> { 
     public Atom1(Space1 someSpace) { 
       super(someSpace); 
     } 
} 
+0

はい、これも動作しますが、あなたに感謝 だから、 '秘密'インタフェースが定義するより具体的な型でgetList()をオーバーライドすることです。 –

0

Javaでパラメータ化された型を作るための唯一の方法は、彼らの実際について全く何も知ら具体的なタイプは、構築時に型パラメータを渡すことです:

public Foo<T>(class<T> klass, // other parameters 

メタ答えは、円形タイプの依存性は疑問であり、あなたのデザインを再検討する必要性を示していることです。一般的に、よりよい解決策は、第三のタイプに階層的依存関係を持つことです。

public class SomeAtom extends Atom<Something> 
public class SomeSpace extends Space<Something> 

メタメタ答えはどんな言語、「型の安全性」は限界があるということではありません:http://www.kdgregory.com/index.php?page=java.generics.cpp

3
abstract class Space<S extends Space<S,A>, A extends Atom <A, S>> {} 
abstract class Atom <A extends Atom <A,S>, S extends Space<S, A>> {} 

それとも、私は推測、あなたが

abstract class Space<S extends Space<S,A>, A extends Atom<S, A>> {} 
abstract class Atom <S extends Space<S,A>, A extends Atom<S, A>> {} 
+0

私はパラメータの順序を一致させる傾向があります。 –

+0

Tomさん、あなたの提案はうまくいきますが、非常に特別なことは動作しません(非常に奇妙です)。私の '答え'のコード全体を見てください。ありがとうございます –

0

ありがとう、好みなら「トムホーティン - tackline」を、私はあなたの答え、 を取り入れてきましたし、それがフィットします。私は彼らのコンテナ型を知っている要素オブジェクトが必要 :また、次のコードは、(あなたが原子の一覧が必要な場合)(少し奇妙な) 必要が

interface ISpace<S extends ISpace<S, A>, A extends IAtom<S, A>> { 
    List<IAtom<? extends S, ? extends A>> getList(); 
} 
interface IAtom<S extends ISpace<S, A>, A extends IAtom<S, A>> { 
    S getSpace(); 
} 

abstract class Space<S extends Space<S, A>, A extends Atom<S, A>> 
    implements ISpace<S, A> { 

    private final List<IAtom<? extends S, ? extends A>> atoms = 
      new LinkedList<IAtom<? extends S, ? extends A>>(); 

    public Space() { 
    } 

    @Override 
    public List<IAtom<? extends S, ? extends A>> getList() { 
     return atoms; 
    } 
} 

abstract class Atom<S extends Space<S, A>, A extends Atom<S, A>> 
    implements IAtom<S, A> { 

    private final S space; 

    public Atom(S someSpace) { 
     this.space = someSpace; 

/// THIS WILL NOT WORK WITHOUT THOSE STRANGE LIST TYPE PARAMETERS 
     space.getList().add(this); 
    } 

    @Override 
    public S getSpace() { 
     return space; 
    } 
} 

class Space1 extends Space<Space1, Atom1> { 
    public Space1() { 
    } 
} 

class Atom1 extends Atom<Space1, Atom1> { 
    public Atom1(Space1 someSpace) { 
     super(someSpace); 
    } 
} 

は全体のことの背後にある考え方は、あるリストの型パラメータを変更することを示してい-safely とその要素を安全にタイプするコンテナオブジェクトです。

+0

すべてを削除しますか?拡張する。 –

+0

また、おそらくAtomにメソッドを追加する必要があります:abstract A getThis();これを生の代わりに使用してください。 –

+0

私が言ったように、 '?それは機能しません。 そして、 'A getThis(){これを返す; } '動作しないのいずれか:( –

1

私はジェネリックでこの問題を解決しようとしません。代わりに、常に一致するオブジェクトを作成するファクトリを指定します。

class UniverseFactory { 
    public Space getSpace(); 
    public Atom getAtom(); 
} 

次に、一致するオブジェクトのみが使用されるように、実装で型チェックを実行できます。

関連する問題