3

私が達成したい基本的なことは、参照List<Ref<Thing>>のリストを実際のオブジェクトのリストにマップすることですが、スーパークラスによって与えられますList<SuperThing>。この例でThing extends SuperThingは、参照先のオブジェクトを取得Ref<Thing>するメソッドがあります。public Thing get()

私が有効だと思った方法:

public <T> List<T> refsToObjects(List<Ref<? extends T>> list) {
    List<T> result = new ArrayList<T>();
    for(Ref<? extends T> ref : list) {
        result.add(ref.get());
    }
    return result;
}

でも使おうとすると

List<Ref<Thing>> refs;
List<SuperThing> objectList = refsToObjects(refs);

次のエラー メッセージが表示されます。The method refsToObjects(List<Ref<? extends T>>) is not applicable for the arguments (List<Ref<Thing>>)

以前はワイルドカード構造を積極的に使用していませんでし? extends Tたが、何が間違っているのでしょうか?

4

5 に答える 5

3

メソッドをList<? extends Ref<? extends T>>代わりに次のように宣言します。

public <T> List<T> refsToObjects(List<? extends Ref<? extends T>> list) { ... }

体内で何かを変える必要はありません。

編集:このソリューションを使用すると、呼び出しサイトで型推論が失敗するようです。のような呼び出しでのみ機能しますthis.<SuperThing>refsToObjects(refs)。したがって、この種の使用法が予想される場合は、追加の型パラメーターを使用するwrm のソリューションが望ましいです。

于 2013-01-03T14:05:37.390 に答える
2

ご覧のとおり、コードには 2 つのエラーがあります。List<Ref<? extends Thing>>1 つ目は、その型が のスーパータイプであると信じることですList<Ref<Thing>>Thinglikeのサブクラスを作成した場合DerivedThing、 のインスタンスRef<DerivedThing>を のリストに追加することはできませんList<Ref<Thing>>

List<Ref<Thing>> refs = new ArrayList<Ref<Thing>>();
refs.add(new Ref<Thing>()); // OK.
refs.add(new Ref<DerivedThing>()); // Error!

ただし、これを次のように置き換えればList<Ref<? extends Thing>>、クラスの問題はなくなりますDerivedThing

List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
refs.add(new Ref<Thing>()); // Still OK.
refs.add(new Ref<DerivedThing>()); // Now OK!

したがって、コンパイラが引数としてList<Ref<? extends Thing>>関数にの値を渡すことを許可した場合、関数は無効な項目をリストに追加することができます。List<Ref<? extends Thing>>

<? extends Thing>2 番目のエラーは、 の基本型 (または消去型)がSuperThingではなく であると考えることThingです。ここでは、 とその派生クラスのコレクションではなく、 とその派生クラスで<? extends Thing>構成される型のコレクションを指定します。したがって、次のように書くことができます。ThingSuperThing

List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
refs.add(new Ref<Thing>());
List<Thing> objectList = refsToObjects(refs);

または、SuperThing消去タイプとして:

List<Ref<? extends SuperThing>> refs = new ArrayList<Ref<? extends SuperThing>>();
refs.add(new Ref<Thing>());
List<SuperThing> objectList = refsToObjects(refs);

List<SuperThing>ただし、は のスーパークラスではないため、両方の組み合わせではありませList<Thing>. ん。したがって、上記の解決策のいずれかを使用するか、出発点として保持したい場合はwrm の解決策を使用してください。Ref<Thing>List<Ref<? extends SuperThing>>List<Ref<Thing>>

個人的には、ポリモーフィズムを最大限に活用し、常にSuperThing;からすべてを参照することを好みます。ThingまたはRef<Thing>オブジェクトを作成する場合でも。たとえば、 type のパラメーターをTのコンストラクターに追加すると、次のようになりRef()ます。

List<Ref<SuperThing>> refs = new ArrayList<Ref<SuperThing>>();
refs.add(new Ref<SuperThing>(new Thing()));
List<SuperThing> objectList = refsToObjects(refs);

のコンストラクタでtypeのオブジェクトを typeThingの参照に渡していることに注意してください。階層のスーパークラスをすべての派生オブジェクトの参照として使用することで、すべてのコーディングがはるかに簡単になります。OOP は、ほとんどすべてのオブジェクトをそのスーパークラスのみを介して表示することを選択した場合に非常にうまく機能し、非常に簡単に機能し、これはジェネリックの使用にまで及びます。SuperThingRef()

于 2013-01-03T18:01:56.097 に答える
0

次のようなことを行う場合にも機能します。

List<Ref<Thing>> refs;
List<SuperThing> objectList = this.<Thing>refsToObjects(refs);

何が起こっているかというと、メソッドが拡張するものを期待しているということですT。しかし、決して定義しませんT。@wrm で説明されているものは、メソッドで定義しています。

于 2013-01-03T11:58:19.807 に答える
0

タイプは正確に一致する必要があるため、次のようになります。

List<Ref<? extends Thing>> refs = new ArrayList<Ref<? extends Thing>>();
List<SuperThing> objectList = refsToObjects(refs);

動作するはずです。

于 2013-01-03T09:44:14.440 に答える