7

私は次のジェネリッククラスを持っています:

class Or<A,B>
{
  Or (A a) {}
  Or (B b) {}
}

コンパイルしようとすると、次のエラーが発生するのはなぜですか。

Or(A) は Or で既に定義されています
    または (B b)
    ^

2 つのコンストラクターは、ジェネリック型の引数が異なりますが、同じシグネチャを共有しているように思えます。なんで?そして、この問題を回避するにはどうすればよいですか?

アップデート

私は今問題を理解しました。コンパイラには、2 つの型を区別する方法が必要です。このような制約を追加することは、私のユース ケースでは問題ありません。だから私は別の質問を追加したいと思います:

2 つのタイプ A と B がまったく異なるものであると指定するにはどうすればよいでしょうか?

4

9 に答える 9

9

2 つのコンストラクターは、ジェネリック型の引数が異なりますが、同じシグネチャを共有しているように思えます。

彼らはそうします。サインは

Or(Object o);

なんで?

Java でのジェネリックの型消去実装のため: ジェネリック型への参照はSystem.Object、それらが使用されるすべてのコンテキストで変換されます。ジェネリック型はコンパイラだけが知っています。

そして、この問題を回避するにはどうすればよいですか?

残念ながら、コンストラクターでこの問題を簡単に回避することはできません。オーバーロードされたコンストラクターをファクトリ メソッドに置き換えて、別の名前を付けることができOrWithAますOrWithB

// Hide the constructor
private Or(...) {
    ...
}
// Publish factory methods
public static <X> Or OrWithA(X a) {
    return new Or(...);
}
public static <X> Or OrWithB(X a) {
    return new Or(...);
}
于 2013-07-03T10:16:23.393 に答える
2

これは型消去によるものです。Eclipse コンパイラは、より詳細なエラーを返します。 Method Or(A) has the same erasure Or(Object) as another method in type Or

ジェネリックに制限を適用すると、問題なくコンパイルされます。

class Or<A extends String, B extends Integer>
{
    または(A a) {}

    または(B b) {}
}
于 2013-07-03T10:18:24.870 に答える
2

彼らはただそうします。これがジェネリックの性質です。それらは、コンパイル時にのみ使用されるシンタティック シュガーを提供します。それを回避する方法はありません。

(質問のコメントを認めます) これは型消去と呼ばれます: http://en.wikipedia.org/wiki/Type_erasureを参照してください

于 2013-07-03T10:13:58.273 に答える
2

これは、A または B は何でもかまいません。また、ジェネリックはコンパイル時だけのものと同じでもかまいません。実行時に、型の消去により失われます

于 2013-07-03T10:14:46.640 に答える
1

別の言い方をすれば、A と B の 2 つのタイプがあり、両方について何も知られていません。したがって、完全に未知のタイプは、別のタイプと同じくらい優れています。コンストラクター呼び出しはどのようにディスパッチする必要がありますか?

于 2013-07-03T10:16:34.570 に答える
0

これは、型の消去が原因です。ジェネリックはコンパイル時に Object 型に置き換えられるため、メソッドは同じシグネチャを持ちます。回避策として、A と B のタイプを絞り込むことを選択できます。

public class Test<A extends String, B extends Number> {

public Test(A arg){

}

public Test(B arg){

}
}
于 2013-07-03T10:17:33.913 に答える
0

これらのコンストラクターは、実行時に型を識別できないため、同じシグネチャを持つと見なされます。

可能であれば、少なくとも 1 つの型パラメーターに境界を指定してみてください。

class Or<A extends Number,B>
{
  Or (A a) {}
  Or (B b) {}
}
于 2013-07-03T10:17:43.203 に答える
0
  1. これを考慮して、どのコンストラクターを呼び出すか?

    Or<Integer,Integer> o = new Or<>(5);
    
  2. あなたの問題は本当にType eraserから来ており、コンパイル後にコードが次のようになります。

    class Or
    {
        Or (Object a) {}
        Or (Object b) {}
    }
    
于 2013-07-03T10:18:16.390 に答える
0

ジェネリックは実行時に破棄されるため、これは正当ではありません (これは型の消去です)。どちらのメソッドにも のプロトタイプがありOr(Object)ます。

唯一の解決策は、OrA()andOrB()メソッドを使用するか、クラス全体を確認することです。

于 2013-07-03T10:13:58.270 に答える