7

重複の可能性:
Map.get(Object key) が (完全に) ジェネリックではない理由は何
ですか? contains(E e) ではなく、contains(Object o) があるのはなぜですか?

ここでわかるように、型 E のテンプレート化された java.util.List には、テンプレート化containsされていないメソッドがありObjectます。代わりに を使用します。誰かが理由を知っていますか?でtrue が返さ
れるのはどのような場合ですか? 私が間違っていなければ、比較対象のオブジェクトが E 型を祖先として持っていない限り (私の文字列の例では最終的であるため不可能です)List<String>myList.contains(new OtherNonString())String

ジェネリック以前のバージョンとの下位互換性を維持するためだけですか? それが理にかなっているユースケースを見逃していますか? 下位互換性のためだけの場合は、非推奨にして ?contains(Object)を作成してみませんcontains(E)か?

編集:
私のサブ質問のいくつかは以前に回答されていました. 参考までに、この質問も確認してください

4

7 に答える 7

7

if it's just for backwards compatibility, why not deprecate contains(Object) and create a contains(E)?

Because contains(Object) and contains(E) have the same type erasure (as you can see in this code sample) and hence would cause compilation errors. Also, deprecating methods was not an option, the top priority back then was to make legacy code work.

于 2012-11-09T16:16:42.823 に答える
2

これは、パラメーターがリストタイプとは異なるタイプであっても、メソッドがtrueを返す可能性があるためです。より正確にcontains(Object o)は、リストに要素eが含まれている場合はtrueを返すため、 trueになりe.equals(o)ます。

たとえば、次のコードは、のタイプがl2許可されていない場合でもtrueを出力しlistます。

List<ArrayList<String>> list = 
    new ArrayList<ArrayList<String>>();

ArrayList<String> l1 = new ArrayList<String>();
l1.add("foo");

list.add(l1);

LinkedList<String> l2 = new LinkedList<String>();
l2.add("foo");

System.out.println(list.contains(l2));

この理由は、別個のクラスArrayListとLinkedListの両方が、異なるサブクラスを区別しないAbstractListからequals実装を継承するためです。2つのオブジェクトに共通のスーパークラスがない場合でも、それらのequals実装が相互に認識し合う可能性があります。

于 2012-11-09T16:27:40.447 に答える
2

ここにはテンプレートを用意する必要がないため、これはいくつかのテストを妨げるだけであり、オブジェクトが必要なクラスにない場合、メソッドはいずれの場合も false と答えます。

テストとtry/catchよりも、関数の戻り値がブール値であるかどうかをチェックする簡単なテストをコードに含める方がはるかに簡単 です。コンパイル時に型をチェックすることでバグを見つけることができるいくつかのケースでは、オーバーヘッドに見合う価値はありません。

于 2012-11-09T16:12:21.653 に答える
1

ジェネリック以前のバージョンとの下位互換性を維持するためだけですか?

いいえ、それは型消去によって処理されます。

そのメソッドは型セーフである必要はなく、実際の型を返す必要がないため、このようになります。

于 2012-11-09T16:19:55.010 に答える
1

理由の 1 つは、contains()リストを変更しないため、型を強制する必要がない可能性があります。

あなたが持っているリンクから:

このリストに指定された要素が含まれている場合、true を返します。より正式には、このリストに (o==null ? e==null : o.equals(e)) となる要素 e が少なくとも 1 つ含まれている場合にのみ true を返します。

于 2012-11-09T16:12:08.250 に答える
0

反例:

List<String> strings = Arrays.asList("hello", "world");
Object o = "hello";
System.out.println(strings.contains(o)); // true

containsメソッドがパラメーターとしての参照を許可しなかった場合、Object上記のコードをコンパイルすることはできません。ただし、o変数はString、実際に指定されたリストに含まれているのインスタンスを参照します。

の結果は、メソッドcontainsの結果によって決定されます。メソッドは、まったく同じ理由で、Object.equals(Object o)引数のタイプも一般として定義します。Object

String hello = "hello";
Object o = "hello";
System.out.println(hello.equals(o)); // true
于 2012-11-09T16:28:43.543 に答える
0

Java のジェネリックは、消去と呼ばれる手法で実装されています。

  • ジェネリック型が指定されていない場合、型は Object に置き換えられます。
  • 別のジェネリック型が指定されている場合、必要に応じて、Java コンパイラは別のオブジェクトへの型キャストを作成します。
  • コンパイラは、拡張ジェネリック型のポリモーフィズムを保持するブリッジ メソッドも生成します。

これが、コンパイルされたバイトコードで実行時にジェネリック型が存在しない理由です。

例えば

public static <T> void printArray ( T [] inputArray ) {
 for ( T element : inputArray )
    System.out.printf("%s ", element) ;

 System.out.println();
}

コンパイラによって消去が実行された後

public static void printArray ( Object [] inputArray ) {
    for ( Object element : inputArray )
      System.out.printf("%s ", element) ;

 System.out.println();
}

この例では、すべての printArray 呼び出しに対して呼び出される、メモリ内のこのコードのコピーは 1 つだけです。

これが行われる理由は、後方互換性のためです。ジェネリックは、Java バージョン 1.5 で初めて導入されました。

Java バージョン < 1.5 では、次のようなリストを定義しました。

List myList = new ArrayList();

そして、このようではありません

List<Integer> myList = new ArrayList<Integer>();

既に記述されている古いコードが壊れないようにするために、コンパイル済みのクラスにジェネリックに関する情報を含めることはできません。

于 2012-11-09T16:33:12.093 に答える