10

私は完全に理解できない Java のジェネリックの動作に遭遇しました (私の .NET バックグラウンドでは)。

public class TestGeneric<T>
{
    public void get (Object arg)
    {
        T temp = (T) arg;

        System.out.println(temp.toString());

        return;
    }
}

TestGeneric<Integer> tg = new TestGeneric<Integer>();
tg.get("Crack!!!");

get で ClassCastException を取得していない理由を教えてStringください"Crack!!!"。また、その ClassCastException をスローするにはどうすればよいですか? Windows 7 x64 で JDK 1.7.0_07 を使用しています。

4

7 に答える 7

16

クラス キャスト例外が発生しない理由は、Java ジェネリックが型消去によって実装されているためです。CLS に大幅な変更を加える必要があった .NET ジェネリックとは異なり、Java ジェネリックはコンパイル時に完全に処理されます。実行時に、へのキャストTは無視されます。実行時に型をチェックするには、 を保存Class<T>し、そのメソッドを使用して、渡されたパラメーターの型をチェックする必要があります。

public class TestGeneric<T>
{
    private Class<T> genClass;
    public TestGeneric(Class<T> t) {genClass = t;}
    public void get (Object arg)
    {
        if (!genClass.isInstance(arg)) {
            throw new ClassCastException();
        }
        T temp = (T) arg;

        System.out.println(temp.toString());

        return;
    }
}

TestGeneric<Integer> tg = new TestGeneric<Integer>(Integer.class);
tg.get("Bang!!!"); // Now that's a real Bang!!!
于 2013-05-22T10:35:13.803 に答える
8

これは、ジェネリック型 T に境界が定義されていないため、オブジェクトとして扱われるためです。この場合、何かを T にキャストしても a は発生しませんClassCastException

ただし、クラス定義がpublic class TestGeneric<T extends Number>の場合、文字列を get() に渡すと ClassCastException が発生します。

于 2013-05-22T10:36:02.863 に答える
7

汎用コードが「消去」された非汎用コードがどのように見えるかを考えるのは、有益な演習です。

public class TestGeneric
{
    public void get (Object arg)
    {
        Object temp = (Object) arg;

        System.out.println(temp.toString());

        return;
    }
}

TestGeneric tg = new TestGeneric();
tg.get("Crack!!!"); // should there be any problem?
于 2013-05-22T22:24:16.713 に答える
4

Java の Generics はコンパイル時のエンティティであることを常に覚えておいてください。実行時には何の関係もありません。あなたの oqn コードのデモをさせてください。

public class TestGeneric<T>
{
    public void get (Object arg)
    {
        T temp = (T) arg;

        System.out.println(temp.toString());
        System.out.println(temp.getClass());

        return;
    }

    public static void main(String args[])
    {
        TestGeneric<Integer> tg = new TestGeneric<Integer>();
        tg.get("Crack!!!");
    }
}

そして出力は

Crack!!!
class java.lang.String

今は理にかなっていますか?オブジェクトは最高のスーパー クラスです。そのため、ポリモーフィズムにより String オブジェクトを取得できます。あなたは型キャストを行っていますが、むしろ文字列オブジェクトへの整数参照ポイントを作成すると言いますJavaは、実行時に文字列オブジェクトであることを内部的に認識します。toString()がInteger クラスで定義されていないと問題が発生します。呼び出す関数は参照で定義する必要がありますが、実装は参照されたオブジェクトから実行時に適切に取得されます。

于 2013-05-22T10:42:51.773 に答える
3

これは によるものtype-erasureです。これは、Java ではすべてのジェネリックがObject実行時に削減されることを意味します。したがって、あなたはあなたをキャストStringしましたが、Objectこれはまったく問題ありません。そしてtoStringに実装されているObjectので、やはり例外ではありません。

ここに型消去に関するリンクがあります

実際に を取得する唯一の方法ClassCastExceptionは、 のインスタンスをClass<T>ジェネリック型に渡し、実行myClass.isInstance(arg)して例外をスローすることです。false

于 2013-05-22T10:33:34.523 に答える
2

IntegerにはメソッドがありtoStringます。実際にはすべてObjectがこのメソッドを持っているため、発生しClassCastExceptionません。

Stringオブジェクトで固有のメソッドを呼び出していないため、例外は発生しませんでした。

この理由は、実行時にタイプ パラメーター beause のタイプerase が表示されないためです。

ポイントは、コードがコンパイルされた後は、ジェネリック型パラメーターが消去されるため、それらを見ることができなくなるということです。

クラスキャスト例外を説明する別の質問がここにあります:説明

そのコードでは、ユーザーがStringジェネリック パラメーター以外に明示的にキャストしようとしたことがわかります。

したがって、これは C# と比較した Java の欠点と言えます。

于 2013-05-22T10:35:18.610 に答える