6

私は、ジェネリック継承と依存関係の広範なツリーを持つプロジェクトに取り組んでいます。より良い例を見るために編集に行きます。基本は次のようになります。

class A {
  ...
}

class B {
  ...
}

class C extends B {
  ...
}

class D<T extends B> extends A {
  ...
}

class StringMap<T extends A> {
   HashMap<String, T> _elements;
   ...
}

それでは、特定のStringMapタイプを含むクラスを作成します。

class X {
  StringMap<D<C>> _thing = new StringMap<D<C>>;
  ... 
}

これまでのところ、これはすべて正常に機能します。D<C>は実際には非常に長い名前であり、特定の組み合わせはコードの他の部分に頻繁に表示されるため、より明確で短い名前になるように、特定の組み合わせのクラスを決定しました。

class DC extends D<C> {

}

//and go to update X
class X {
  StringMap<D<C>> _thing = new StringMap<D<C>>(); //still works fine
  StringMap<DC> _thing = new StringMap<DC>(); //error
  ... 
}

Eclipseは次のエラーを出します

バインドされた不一致:タイプは、タイプDCの制限されたパラメーターの有効な代替ではありません<T extends A>StringMap<T>

だから問題は、なぜこれがうまくいかないのかということです。DCコンストラクターを拡張D<C>してエコーするだけです。それが除外するものの単なる子クラスであるのに、なぜ異なるとStringMap見なされるのですか?DC

編集:
OK、私が実際に行っていることに近づけるために例を作り直しました。テストしましたが、エラーが発生します。私がここで行っているのは、ジェネリック型を使用しclone()て、継承ツリーでそれを実装する人に正しいクラスを返すようにすることです。次に、サブクラスでは、のサブクラスがジェネリック型としてBのサブクラスB<T extends B<T>>を確実に渡すために使用しています。BT

public abstract class Undoable<T> implements Comparable<T> {
  public abstract T clone();
  public abstract void updateFields(T modified);
}

abstract public class A<T extends A<T, U>, U extends Comparable<U>>
    extends Undoable<T> {
  abstract U getKey();

  @Override
  public int compareTo(T element)
  {
    return getKey().compareTo(element.getKey());
  }
}

public class B<T extends B<T>> extends A<T, String> {
  @Override
  public T clone()
  {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public void updateFields(T modified)
  {
    // TODO Auto-generated method stub
  }

  @Override
  String getKey()
  {
    // TODO Auto-generated method stub
    return null;
  }
}

public class C extends B<C> {

}

public class D<T extends B<T>> extends A<D<T>, String> {
  @Override
  String getKey()
  {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public D<T> clone()
  {
    // TODO Auto-generated method stub
    return null;
  }

  @Override
  public void updateFields(D<T> modified)
  {
    // TODO Auto-generated method stub
  }
}

public class DC extends D<C> {

}

public class StringMap<T extends Undoable<T>> {
  HashMap<String, T> _elements;

}

public class Main {
  public static void main(String[] args)
  {
    StringMap<D<C>> _thing = new StringMap<D<C>>(); //works
    StringMap<DC> _thing1 = new StringMap<DC>(); //error
//Bound mismatch: The type DC is not a valid substitute for
//the bounded parameter <T extends Undoable<T>> of the type StringMap<T>

  }
}
4

4 に答える 4

8

以下は正常に機能するため、何か間違ったことをしているに違いありません。

import java.util.HashMap;

public class Q {
    class A {
    }
    class B {
    }
    class C extends B {
    }
    class D<T extends B> extends A {
    }

    class StringMap<T extends A> {
        HashMap<String, T> _elements;
    }

    class DC extends D<C> {

    }

    //and go to update X
    class X {
        StringMap<D<C>> thing1 = new StringMap<D<C>>(); // still works fine
        StringMap<DC> thing2 = new StringMap<DC>(); // NO error!!!
    }
}

エラーを再現するようなクラスを投稿してみてください。

于 2011-01-20T18:47:14.627 に答える
4

前述のように、コードは問題ありませんが、推測できる場合は、次の行を書くつもりでしたが、実際にはエラーが発生します。

StringMap<D<C>> _thing = new StringMap<DC>; //error

その理由は、次のような問題を引き起こす原因と同じです。

ArrayList<Number> = new ArrayList<Integer>();

識別子の型を定義するときに、つまり左辺値でクラスに指定されたジェネリック型パラメーターは、左辺値で指定されたパラメーターを継承するパラメーターを持つ型によって、つまり右辺値でインスタンス化できません。パラメーターが異なる場合、直観的には互換性があるはずですが (ジェネリックが言語で少し異なって実装されている場合)、型は互換性があるとは見なされません。

それはちょっとした落とし穴です...

于 2011-01-20T19:01:12.920 に答える
2

なぜこれを実行したいのか、StringMap を何に使用したいのか正確にはわかりませんが、StringMap の定義をこれに変更すると、行ったことをコンパイルできるようになります。

class StringMap<T extends Undoable<? super T>> {
  HashMap<String, T> _elements;
}

つまり、型 T は、その型が T の反変 (実際には T 自体) である限り、任意の型の Undoable でなければなりません。だから今、あなたはこれを行うことができます:

StringMap<DC> _thing1 = new StringMap<DC>(); // no more error
_thing1._elements.put("a key", new DC());

とは言っても、これは単なる理論的な演習です。このような複雑な継承階層を使用しないことを強くお勧めしますが、完全なユースケースなしで代替案を提案することは困難です.

それが役立つことを願っています!

于 2011-01-28T13:38:24.257 に答える
0

うーん。これが古いものではないことを願っていますが、私も抱えていた問題を解決しています。D では、D が B を拡張する必要があるか、Cが A のループアラウンドのためにD を拡張する必要があることに気付きました。問題は StringMap クラスにあります。このクラスは、独自の入力がジェネリック クラスを拡張することを厳密に望んでおり、そのジェネリックはその入力でなければなりません。

D は拡張内で言及されているクラスと同じであるため、D は機能します。安全です。D は自分自身を指します。D は A, String> を拡張します。D は Undoable> を実装しているため、D は Undoable> を拡張する A、String> を拡張するため、それを使用して StringMap を作成することは良いことです。一方、DC は Undoable も実装する必要がありますが、これは D のみを拡張するため不可能です。解決策は、DC を使用したメソッドの新しい定義が機能するために必要な Undoable も実装することです。これがあなたが直面している本当の問題です。これで問題が解決することを願っています。

私の古い問題:

クラス D では、T は B を拡張しますが、D は A> を拡張します。ただし、期待される A または A> を返す代わりに、A, String> を拡張します。ただし、D は B を拡張しません。したがって、A、String>、および A の両方。Java では、異なるジェネリック エンクローズ クラスを持つ 2 つの同じインターフェイスからの継承は実装されていないため、T は D を拡張する必要があります。ただし、C は Dを拡張しません。これは、発生している問題です。は、将来修正する必要があるかもしれない問題です。
于 2012-06-14T02:52:27.637 に答える