此代码的输出对您有意义吗?它给出了这个输出:
class java.lang.String
class java.lang.Integer
class java.lang.String
因此,似乎在启动测试对象时将类型分配给Integer,但成员的类型在运行时期间会发生变化。为什么会这样?
public class Test {
public static void main(String[] args) {
MyType<Integer> test = new MyType<Integer>("hello", 1, "world");
}
public static class MyType<T> {
private T member;
public MyType(Object o, Object o2, Object o3) {
T t = (T) o;
member = (T) o2;
System.out.println(t.getClass());
System.out.println(member.getClass());
member = (T) o3;
System.out.println(member.getClass());
}
}
}
答案 0 :(得分:4)
看似奇怪的行为是由于java如何使用类型擦除来实现泛型。您可以查看this question以获取有关类型擦除的更详细说明,但我可以在此方案中总结它的效果。
致电
new MyType<Integer>("hello", 1, "world");
看起来构造函数试图同时转换int类型&#34; 1&#34;和字符串类型&#34;世界&#34;到&#34;会员&#34;实例变量,其类型为Integer:
member = (T) o2;
System.out.println(t.getClass());
System.out.println(member.getClass());
member = (T) o3;
然而,在运行时,这不是正在发生的事情 - 在编译时,类型擦除,泛型中使用的类型被删除&#34;并且内部类代码被编译为:
public static class MyType {
private Object member;
public MyType(Object o, Object o2, Object o3) {
Object t = o;
member = o2;
System.out.println(t.getClass());
System.out.println(member.getClass());
member = o3;
System.out.println(member.getClass());
}
}
所以此时Object类型被分配给Object类型,不会导致任何错误 - 尽管实际引用的对象是不同的类型(o2是int,o3是String)。这就是为什么member.getClass()返回引用的实际类(在本例中为Integer和String)。
那么通用参数何时是
<Integer>
实际上是发挥了作用?当它被使用。我对您的代码进行了一些小修改,尝试访问成员字段并在其上调用Integer方法:
public class Test {
public static void main(String[] args) {
MyType<Integer> test = new MyType<Integer>("hello", 1, "world");
// attempting to use the member variable as an Integer
System.out.println(test.getMember().doubleValue());
}
public static class MyType<T> {
private T member;
public MyType(Object o, Object o2, Object o3) {
T t = (T) o;
member = (T) o2;
System.out.println(t.getClass());
System.out.println(member.getClass());
member = (T) o3;
System.out.println(member.getClass());
}
public T getMember() {
return member;
}
}
}
尝试运行代码会引发以下异常:
Exception in thread "main" java.lang.ClassCastException:
java.lang.String cannot be cast to java.lang.Integer
当test.getMember()。doubleValue()被调用时,编译器会尝试将其强制转换为您的Integer泛型参数 - 但是您将其设置为(&#34; world&#34;)的参数是一个String抛出ClassCastException。编译后的调用看起来像这样:
System.out.println(((Integer) test.getMember()).doubleValue());
请注意,如果&#34;成员&#34;会发生同样的事情。是公开的,我跳过使用getter(如test.member.doubleValue())。
所以基本上你的ClassCastException被延迟了,因为类型被删除了。关于此的Oracle文档作为资源非常有用:https://docs.oracle.com/javase/tutorial/java/generics/genMethods.html。如果有人知道更好,请在必要时纠正我对类型擦除的解释。感谢。
答案 1 :(得分:-1)
它没有改变,你将对象转换为另一种类型,但引用是相同的。在将对象转换为错误类型的意义上,您的代码是错误的。但由于referance是原始对象,getClass将返回真实对象的类型。 如果您使用这些变量,则可能会导致应用程序崩溃。