2

この記事を読んでいる間、私はここで立ち往生しました。これはリンクから貼り付けます。理由が分からない、List<Number>またはList<? extends Number>ここでは使用できない。

public void doStuff( List<Integer> list ) {     
    list.add(1);
    // do stuff
    list.get(0);    
}

We can generalize this one step further by generalizing the generic parameter:

public void doStuff( List<? super Integer> list ) {     
    list.add(1);
    // do stuff
    list.get(0);    
}

一部の読者は、より直感的に List<Number> をここで使用できない理由を尋ねるかもしれません。実際、メソッドを List<Number> または List<? Number> を拡張しますが、最初の定義は実際の ArrayList<Integer> を渡す可能性を排除しますが、2 番目の定義は add() メソッドを許可しません (別の方法で誰かが ArrayList<Float> を渡す可能性があるため、 doStuff の呼び出し後に Float の間にある整数)。

4

4 に答える 4

1

Java はおそらく少し混乱を招きます。これは、二重基準が少し働いているためです。

まず、配列とコレクションの両方が参照型であることを考慮する必要があります。つまり、それらのインスタンスは、データがヒープ メモリに割り当てられ、参照ポインターによって示されるオブジェクトです。

したがって、配列とコレクションの両方に、オブジェクト自体の型と、配列またはコレクション内の各コンポーネントの型の2 つの型があります。これを具体的にするために、以下に例を示します。

String[] strings = new String[] { "AA", "BB", "CC" };

作成されるオブジェクトString[]のタイプは で、すべてのコンポーネントのタイプは ですString

配列は共変であるため、JVM はオブジェクト タイプとコンポーネント タイプの両方を一緒にキャストできます。これが、このような割り当てが有効である理由です。

Object[] objects = strings;

配列の場合、Objectは のスーパータイプであるためStringObject[]も のスーパータイプですString[]。配列は共変です。

これは、配列ではない参照型には適用されません。コレクション。コレクションは不変です。したがって、 aIntegerは のサブタイプですがNumber、コレクションは不変でありList<Integer>、 のサブタイプではありませんList<Number>

于 2013-10-24T22:42:11.453 に答える
0

最初のケースでは、 a を受け入れると( 、、 ...) の要素List<Number> のみが許可され、他のタイプ ( を含む) の は許可されません。リストは、呼び出し関数に(または、または、または ...) として具体的に入力する必要があります。つまり、リストの型は柔軟ですが、ジェネリック引数はそうではありません。ListArrayListLinkedListNumberListIntegerList<Number>ArrayList<Number>LinkedList<Number>

2 番目のケースでは、「is a」という文言を使用すると意味が通じます。はInteger"is a"Numberですが、その逆は必ずしも真ではありません。この例のコードは、関数内で使用されているすべての値が整数であると想定しているため、ジェネリックに制限を設けて、特定性の低いものIntegerを渡さないようにする必要があります。

于 2013-10-24T22:59:40.540 に答える
-1

次の 2 つのことを調べる必要があります。

  1. 署名でのワイルドカードの意味void doStuff(Foo<? super Bar> foo)
  2. メソッド本体内のワイルドカードの意味

Java には、 と の間のサブタイプの関係を決定する非常に単純なルールが 1 つしかFoo<A>ありませんFoo<B>none は other のサブタイプです。ジェネリック型は不変であると私たちは言います。Java 設計者がこのようにしたという理由があるとしても、あなたの観点からは、それは恣意的な決定です。

私たちを混乱させるのは山かっこです、かわいそうな開発者: 私たちはそれを受け入れることに何の問題もFooBarありFooQooません。しかし、何らかの理由で、それを信じる必要がFoo<Qoo>ありFoo<Bar>ます。いいえ、そうではありません。

AとBがどのように関係していても関係X<A>ありX<B>ません。

AとBがどのように関係していても関係X<A>ありX<B> ません。

AとBがどのように関係していても関係X<A> ありX<B>ません。

上記のことを確信したら、次のスニペットを観察してください。

List<Double> doubles = ...;
List<Integer> integers = ...;

Number firstDouble = doubles.get(0);
Number firstInteger = integers.get(0);

get(0)両方のリストを呼び出すと、Number 互換のオブジェクトが得られます。get()の呼び出しを次のようなメソッドに入れたいと思うかもしれgetFirstOfList(list)ませんが、まったく関係のない 2 つの型を受け入れるため、そのようなメソッドは存在できないことを学びました。

ここでワイルドカードの出番です!get()a List<Number>、 a List<Integer>、 a (など)を呼び出すとNumber 互換オブジェクト (つまり、そのサブタイプList<Double>) が返されるので、これを言語レベルで表現する方法が必要です。Java 設計者は、次のように機能するワイルドカードを提供してくれました。Number

public void doStuff(List<? extends Number> arg);

次の無限リストを宣言するのと同じ効果があります。

public void doStuff(List<Number> arg);
public void doStuff(List<Integer> arg);
public void doStuff(List<Double> arg);
public void doStuff(List<Float> arg);
public void doStuff(List<BigDecimal> arg);
...

ワイルドカードのデバイスがなければ、サポートされているリスト タイプごとに 1 つのメソッドを記述する必要があります (これは Java では違法ですが、それは別の話です)。

この例で使用したワイルドカードには、キーワードで識別される上限があります。extends代わりに、貼り付けたスニペットは、メソッド シグネチャで下限superのワイルドカードを採用しています ( )。実際には、次のような理由でいくつかのエラーが含まれている可能性があります。

  1. List<Integer>to を渡すことはできませんdoStuff()
  2. Objectからのみ取得できますlist.get(index)

署名は

void doStuff(List<? super Number> arg);

有限リストを表します:

void doStuff(List<Number> arg);
void doStuff(List<Object> arg);

Number好きなものを に入れることができますが、そこからList<? super Number>しか入れられませんget() Object

于 2013-10-24T23:48:58.123 に答える