Java でジェネリック クラスを作成する場合 (クラスにはジェネリック型パラメーターがあります)、ジェネリック メソッドを使用できますか (メソッドはジェネリック型パラメーターを取ります)。
次の例を検討してください。
public class MyClass {
public <K> K doSomething(K k){
return k;
}
}
public class MyGenericClass<T> {
public <K> K doSomething(K k){
return k;
}
public <K> List<K> makeSingletonList(K k){
return Collections.singletonList(k);
}
}
ジェネリック メソッドで期待されるように、任意のオブジェクトdoSomething(K)
で のインスタンスを呼び出すことができます。MyClass
MyClass clazz = new MyClass();
String string = clazz.doSomething("String");
Integer integer = clazz.doSomething(1);
MyGenericClass
ただし、ジェネリック型を指定せずにのインスタンスを使用しようとすると、渡されたものに関係なく、 を呼び出すとdoSomething(K)
が返されます。Object
K
MyGenericClass untyped = new MyGenericClass();
// this doesn't compile - "Incompatible types. Required: String, Found: Object"
String string = untyped.doSomething("String");
奇妙なことに、戻り値の型がジェネリック クラスの場合はコンパイルされますList<K>
(実際には、これは説明できます - 以下の回答を参照してください)。
MyGenericClass untyped = new MyGenericClass();
List<String> list = untyped.makeSingletonList("String"); // this compiles
また、ワイルドカードのみであっても、ジェネリック クラスが型指定されている場合はコンパイルされます。
MyGenericClass<?> wildcard = new MyGenericClass();
String string = wildcard.doSomething("String"); // this compiles
型指定されていないジェネリック クラスでジェネリック メソッドを呼び出すことが機能しない正当な理由はありますか?
私が見逃しているジェネリッククラスとジェネリックメソッドに関連する巧妙なトリックはありますか?
編集:
明確にするために、型指定されていない、または生の型指定されたジェネリック クラスは、ジェネリック クラスの型パラメーターを尊重しないと予想します (それらが提供されていないため)。ただし、型指定されていない、または型指定されていないジェネリック クラスが、ジェネリック メソッドが尊重されないことを意味する理由は明らかではありません。
この問題は SO ですでに提起されていることが明らかになりました。この質問を参照してください。これに対する答えは、クラスが型付けされていない/生の形式の場合、ジェネリックメソッドの型付けを含め、すべてのジェネリックがクラスから削除されることを説明しています。
しかし、なぜそうなのかについては、まったく説明がありません。それでは、私の質問を明確にさせてください:
- Java が型指定されていない、または raw 型のジェネリック クラスでのジェネリック メソッドの型付けを削除するのはなぜですか? これには正当な理由がありますか、それとも単なる見落としでしたか?
編集 - JLS の議論:
これはJLS 4.8で扱われることが (前の SO の質問とこの質問への回答で) 提案されており、次のように述べられています。
コンストラクター (§8.8)、インスタンス メソッド (§8.4、§9.4)、または非静的フィールド (§8.3) の型 M スーパークラスまたはスーパーインターフェイスから継承されていない生の型 C は、対応する生の型です。 C に対応するジェネリック宣言での型の消去に。
これが型指定されていないクラスにどのように関連するかは明らかです。クラスのジェネリック型は消去型に置き換えられます。クラスジェネリックがバインドされている場合、消去タイプはそれらの境界に対応します。それらがバインドされていない場合、消去タイプはオブジェクトです-例
// unbound class types
public class MyGenericClass<T> {
public T doSomething(T t) { return t; }
}
MyGenericClass untyped = new MyGenericClass();
Object t = untyped.doSomething("String");
// bound class types
public class MyBoundedGenericClass<T extends Number> {
public T doSomething(T t) { return t; }
}
MyBoundedGenericClass bounded = new MyBoundedGenericClass();
Object t1 = bounded.doSomething("String"); // does not compile
Number t2 = bounded.doSomething(1); // does compile
ジェネリック メソッドはインスタンス メソッドですが、JLS 4.8 がジェネリック メソッドに適用されるかどうかはわかりません。ジェネリック メソッドの型 (<K>
前の例) は型指定されていません。その型はメソッド パラメーターによって決定されるためです。