7

最初のメソッドはコンパイルされ、2 番目のメソッドはコンパイルされないのはなぜですか? SetとのジェネリックImmutableSet.Builderは同じで、メソッドの型シグネチャaddも同じです。

import java.util.Set;
import java.util.HashSet;
import com.google.common.collect.ImmutableSet;

public class F {

    public static ImmutableSet<? extends Number> testImmutableSetBuilder() {
        ImmutableSet.Builder<? extends Number> builder = ImmutableSet.builder();
        Number n = Integer.valueOf(4);
        builder.add(n);
        return builder.build();
    }

    public static Set<? extends Number> testJavaSet() {
        Set<? extends Number> builder = new HashSet<Number>();
        Number n = Integer.valueOf(4);
        builder.add(n);
        return builder;
    }
}

ビルドに javac バージョン 1.7.0_25 を使用しています。2 番目の方法では次のエラーが発生しますが、最初の方法では発生しません。Numberのコレクションにa を入れるのは型が正しくないため、どちらの場合でもエラーが発生するはずです? extends Number

error: no suitable method found for add(Number)
        builder.add(n);
               ^
    method Set.add(CAP#1) is not applicable
      (actual argument Number cannot be converted to CAP#1 by method invocation conversion)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Number from capture of ? extends Number
4

4 に答える 4

1

答えが見え始めたと思います。ImmutableSet.Builderメソッドaddがオーバーロードされている場合、別の署名がありますadd(E... elements)。結果の .class ファイルを実行javap -vしたところ、この代替メソッドが実際に呼び出されていることがわかりました。varargselementsは実際には隠れた Java 配列であり、Java 配列は共変です。つまり、この特定の例に関しては、

builder.add(n);

Number n、タイプ の単一要素配列に変換されNumber[]ます。<? extends Number>しかし、その配列が合法的に!の配列に変換される方法がわかりません。

于 2013-10-23T17:14:52.240 に答える
0

GET&PUTの原理というものがあります。常にそれに従うことをお勧めします。

GET & PUT の原則

「構造体から値を取得するだけの場合は extends ワイルドカードを使用し、値を構造体に入れるだけの場合はスーパー ワイルドカードを使用し、get と put の両方を行う場合はワイルドカードを使用しないでください」

于 2014-02-24T09:52:35.983 に答える