22

コンパイルされない次のコードがあります。コンパイルする方法はありますが、コンパイルされない理由を理解したいと思います。最後に投稿するエラーメッセージが表示される理由を誰かに教えてもらえますか?

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

4

3 に答える 3

24

その理由は、Test.classのタイプがClass<Test>であるためです。Class <Test>型の参照を、Class <T>型の変数に割り当てることはできません。これらは、同じものではないためです。ただし、これは機能します。

Class<? extends Test> testType = type == null ? Test.class : type;

ワイルドカードを使用すると、Class<T>とClass<Test>の両方の参照をtestTypeに割り当てることができます。

Angelika Langer Java Generics FAQには、Javaジェネリックの動作に関する大量の情報があります。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をタイプの変数に割り当てることはできません。この例では、は実際にはであり、これをに割り当てることはできません。実際、エラーはタイプの不一致でもあります。IntegerNumberNumberLongIntegerType mismatch: cannot convert from Number to Integer

互換性の保証がないため、インスタンスのタイプのサブクラスである変数にインスタンスを割り当てることはできません。

ジェネリックスも同様に動作します。ジェネリックメソッドシグニチャでTは、は、メソッドがコンパイラに何を許可するかを示すための単なるプレースホルダーです。コンパイラーが検出するtestNumber(Integer.class)と、基本的に。に置き換えTられIntegerます。

ワイルドカードは、以下をコンパイルするため、柔軟性を追加します。

Class<? extends Number> wildcard = numberClass;

これClass<? extends Number>は、NumberまたはこのサブクラスであるすべてのタイプNumberが完全に合法であり、多くの状況で役立つ可能性があることを示しています。

于 2008-10-02T16:54:15.250 に答える
4

テストを拡張するとします。

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を a として宣言するClass<? extends Test>のが正しい解決策です。へのキャストClass<T>は本当の問題を隠しています。

于 2008-10-03T00:38:10.500 に答える
1

条件を削除すると、エラーが少し良くなります...

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;
于 2008-10-02T16:52:02.057 に答える