コンパイルされない次のコードがあります。コンパイルする方法はありますが、コンパイルされない理由を理解したいと思います。最後に投稿するエラーメッセージが表示される理由を誰かに教えてもらえますか?
public class Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(null);
}
public <T extends Test> void testT(Class<T> type) {
Class<T> testType = type == null ? Test.class : type; //Error here
System.out.println(testType);
}
}
Type mismatch: cannot convert from Class<capture#1-of ? extends Test> to Class<T>
Test.class
をClass<T>
にキャストすることにより、これはUnchecked cast
警告とともにコンパイルされ、完全に実行されます。
その理由は、Test.classのタイプがClass <Test>であるためです。 Class <Test>型の参照は、同じものではないため、Class <T>型の変数に割り当てることはできません。ただし、これは機能します。
_Class<? extends Test> testType = type == null ? Test.class : type;
_
ワイルドカードを使用すると、Class <T>とClass <Test>の両方の参照をtestTypeに割り当てることができます。
Javaジェネリックスの動作 Angelika Langer JavaジェネリックスFAQ )に関する情報はたくさんあります。 Number
クラス階層JavaのコアAPIを使用する情報の一部。
次の方法を検討してください。
_public <T extends Number> void testNumber(final Class<T> type)
_
これは、次のステートメントを正常にコンパイルできるようにするためです。
_testNumber(Integer.class);
testNumber(Number.class);
_
ただし、以下はコンパイルされません。
_testNumber(String.class);
_
ここで、次のステートメントについて考えてみましょう。
_Class<Number> numberClass = Number.class;
Class<Integer> integerClass = numberClass;
_
2行目はコンパイルに失敗し、このエラー_Type mismatch: cannot convert from Class<Number> to Class<Integer>
_を生成します。しかし、Integer
はNumber
を拡張しているのに、なぜ失敗するのでしょうか。次の2つのステートメントを見て、理由を確認してください。
_Number anumber = new Long(0);
Integer another = anumber;
_
2行目がここでコンパイルされない理由は簡単にわかります。 Number
インスタンスが互換性のあるタイプであることを保証する方法がないため、Integer
のインスタンスをタイプNumber
の変数に割り当てることはできません。この例では、Number
は実際にはLong
であり、これをInteger
に割り当てることはできません。実際、エラーはタイプの不一致でもあります:_Type mismatch: cannot convert from Number to Integer
_。
互換性の保証がないため、インスタンスのタイプのサブクラスである変数にインスタンスを割り当てることはできません。
ジェネリックスも同様に動作します。汎用メソッドシグネチャでは、T
は、メソッドがコンパイラに何を許可するかを示す単なるプレースホルダーです。コンパイラがtestNumber(Integer.class)
を検出すると、基本的にT
をInteger
に置き換えます。
ワイルドカードは、以下がコンパイルされるため、柔軟性を追加します。
_Class<? extends Number> wildcard = numberClass;
_
_Class<? extends Number>
_は、Number
またはNumber
のサブクラスである任意の型を示すため、これは完全に合法であり、多くの状況で役立つ可能性があります。
テストを拡張するとします。
public class SubTest extends Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(new SubTest());
}
}
さて、testT
を呼び出したとき、型パラメーター<T>
はSubTest
です。これは、変数testType
がClass<SubTest>
であることを意味します。 Test.class
はタイプClass<Test>
であり、タイプClass<SubTest>
の変数に割り当てることはできません。
変数testType
をClass<? extends Test>
として宣言するのが正しい解決策です。 Class<T>
にキャストすると、実際の問題が隠されます。
条件文を削除すると、エラーは少し良くなります...
public class Test {
public static void main(String args[]) {
Test t = new Test();
t.testT(null);
}
public <T extends Test> void testT(Class<T> type) {
Class<T> testClass = Test.class;
System.out.println(testClass);
}
}
Test.Java:10: incompatible types
found : Java.lang.Class<Test>
required: Java.lang.Class<T>
Class<T> testClass = Test.class;