使用Java中的泛型键入安全性

sta*_*ort 10 java generics

我在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!!!");
Run Code Online (Sandbox Code Playgroud)

请告诉我为什么我没有得到ClassCastException,而且,在Idea中我看到temp String在赋值后具有值"Crack!!!".另外,我怎么能抛出ClassCastException?我在Windows 7 x64上使用JDK 1.7.0_07.

das*_*ght 14

您没有获得类转换异常的原因是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!!!
Run Code Online (Sandbox Code Playgroud)


小智 7

这是因为泛型类型T没有定义的边界,因此它被视为一个Object.ClassCastException在这种情况下,将某些东西投射到T不会导致.

但是,如果您的类定义是public class TestGeneric<T extends Number>,那么如果将String传入get(),则会得到ClassCastException.


new*_*cct 6

考虑通用代码被"擦除"的非通用代码看起来是一种有益的练习:

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?
Run Code Online (Sandbox Code Playgroud)


Jax*_*xox 5

如果你这样做,你甚至不需要检查ClassCastException,它甚至无法编译。

public class TestGeneric<T> {
    public void get (T arg){
        System.out.println(arg.toString());
    } 
}

TestGeneric<Integer> tg = new TestGeneric<Integer>();
tg.get("Crack!!!");
Run Code Online (Sandbox Code Playgroud)