Java 中的泛型类型安全
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16689477/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Type safety with generics in Java
提问by starteleport
I've encountered a behaviour of generics in Java that I completely can't understand (with my .NET background).
我在 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!!!");
Please tell me why I'm not getting ClassCastException in get, moreover, in Idea I see temp as String
after assignment and having value of "Crack!!!"
. Also, how could I have that ClassCastException throwed? I'm using JDK 1.7.0_07 on Windows 7 x64.
请告诉我为什么我没有在 get 中得到 ClassCastException,此外,在 Idea 中,我认为 temp 是String
在赋值之后并且具有"Crack!!!"
. 另外,我怎么能抛出 ClassCastException 呢?我在 Windows 7 x64 上使用 JDK 1.7.0_07。
回答by dasblinkenlight
The reason you are not getting a class cast exception is that Java generics are implemented through type erasure. Unlike .NET generics that required significant changes to CLS, Java generics are processed entirely in compile-time. At runtime, the cast to T
is ignored. In order to check type at runtime, you need to store Class<T>
, and use its methods to check the type of a parameter passed in:
您没有收到类转换异常的原因是 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!!!
回答by nitegazer2003
This is because the generic type T has no defined bounds so it is treated as an Object. Casting something to T will not cause a ClassCastException
in this case.
这是因为泛型类型 T 没有定义的边界,所以它被视为一个对象。ClassCastException
在这种情况下,将某些内容投射到 T 不会导致 a 。
However, if your class definition was public class TestGeneric<T extends Number>
, then you would get the ClassCastException if you passed in a String into get().
但是,如果您的类定义是public class TestGeneric<T extends Number>
,那么如果您将 String 传入 get(),则会得到 ClassCastException。
回答by newacct
It is an instructive exercise to think about what the non-generic code that the generic code is "erased to" looks like:
思考泛型代码被“擦除”到的非泛型代码是什么样的,这是一个有益的练习:
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?
回答by Jaxox
If you do it this way, you don't even need to check the ClassCastException and it won't even be able to compile.
如果你这样做,你甚至不需要检查 ClassCastException,它甚至无法编译。
public class TestGeneric<T> {
public void get (T arg){
System.out.println(arg.toString());
}
}
TestGeneric<Integer> tg = new TestGeneric<Integer>();
tg.get("Crack!!!");
回答by Aniket Thakur
Always remember Generics in Java are compile time entities. It has nothing to do at runtime. Let me demo your oqn code to you.
永远记住 Java 中的泛型是编译时实体。它在运行时无关。让我向您演示您的 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!!!");
}
}
and the output is
输出是
Crack!!!
class java.lang.String
Makes sense now? Objectis the supreme super class. So it can get a String object due to polymorphism. Though you are type casting or rather i will say making an integer reference point to a string object Java know internally it is a String object at runtime. There would have been a problem if toString()was not definedin Integer class. The function you call must be definedin the reference but the implementation will be picked up appropriately at runtimefrom the referenced object.
现在有意义吗?Object是最高的超类。所以由于多态,它可以得到一个 String 对象。尽管您是类型转换,或者更确切地说,我会说使一个整数引用指向一个字符串对象,Java 在内部知道它在运行时是一个 String 对象。如果toString()没有在 Integer 类中定义,就会出现问题。您调用的函数必须在引用中定义,但将在运行时从引用的对象中适当地选取实现。
回答by John B
This is due to type-erasure
. This means that in Java all generics are reduced to Object
at run-time. So you have casted your String
to Object
which is totally fine. And since toString
is implemented on Object
, again no exception.
这是由于type-erasure
. 这意味着在 Java 中所有泛型都减少到Object
运行时。所以,你有你的铸造String
到Object
这是完全的罚款。并且由于toString
在 上实施Object
,因此也不例外。
Here is a link on type-erasure
这是有关类型擦除的链接
The only way to really get the ClassCastException
is to pass an instance of Class<T>
to the generic type and then do myClass.isInstance(arg)
and throw an exception if false
真正获得 的唯一方法ClassCastException
是将 的实例传递Class<T>
给泛型类型,然后执行myClass.isInstance(arg)
并抛出异常,如果false
回答by Adam Arold
The type Integer
has a method toString
. In fact every Object
has this method so ClassCastException
will not occur.
该类型Integer
有一个方法toString
。事实上每个人Object
都有这个方法所以ClassCastException
不会发生。
You did not call any String
-specific method on your object thus no exception occured.
您没有String
在对象上调用任何特定的方法,因此没有发生异常。
The reason for this is that at runtime you will not see the type parameters beause of type erasure.
这样做的原因是在运行时您不会因为类型擦除而看到类型参数。
The point is that after your code is compiled you are no longer to be able to see the generic type parameters because they are erased.
关键是在编译代码后,您将不再能够看到泛型类型参数,因为它们已被擦除。
There is another question here which explains class cast exception: explanation
这里有另一个问题解释了类转换异常:解释
In that code you can see that the user tried to cast explicitly to String
not to a generic parameter.
在该代码中,您可以看到用户尝试显式转换String
为非通用参数。
So you can call this a shortcoming of java compared to C#.
因此,您可以将其称为 Java 与 C# 相比的缺点。