我一直在阅读Java Generics Tutorials和Stackoverflow中很少涉及泛型的线程,但仍然无法理解具体案例。 这是:
public class Box<T>
{
private T t;
public T getT ()
{
return t;
}
public void setT (T t)
{
this.t = t;
}
public static void main (String[] args)
{
Box<Integer> intBox = new Box<Integer>();
Box rawBox = intBox;
rawBox.setT("NBA");
System.out.println(rawBox.getT());
System.out.println(intBox.getT());
/*1*/ //System.out.println(intBox.getT().toString());
}
}
这是交易,我理解的第一个印刷品,即
System.out.println(rawBox.getT());
打印NBA,因为rawBox是原始类型的Box T,它“给”我们对象。
我没有得到的是第二次印刷:
System.out.println(intBox.getT());
打印NBA。 intBox是泛型类型(在本例中为Box of Integers),这意味着它的getter方法应该返回一个类型为T的值(在本例中为Integer),所以我理解的是那里保存的String对象应该被转换to Integer(因为这是给Box T的参数类型),并且应该在运行时引发ClassCastException,但它不会发生,为什么会这样?
顺便说一句,注释号/ 1 /会增加混乱,因为如果我要取消注释它,它会导致在ruuntime中引发ClassCastException(String不能转换为Integer) ,我不明白
全部谢谢:)
答案 0 :(得分:2)
有时很难猜出Java会在哪里插入已检查的强制转换。通常,它只会在必要时插入它们。理解你看到的行为的最好方法是检查字节码!
如果我们运行javap -c Box.class
(在使用/*1*/
未注释进行编译之后),我们会看到:
public static void main(java.lang.String[]);
Code:
...
20: invokevirtual #8 // Method getT:()Ljava/lang/Object;
23: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
26: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
29: aload_1
30: invokevirtual #8 // Method getT:()Ljava/lang/Object;
33: invokevirtual #9 // Method java/io/PrintStream.println:(Ljava/lang/Object;)V
36: getstatic #7 // Field java/lang/System.out:Ljava/io/PrintStream;
39: aload_1
40: invokevirtual #8 // Method getT:()Ljava/lang/Object;
43: checkcast #10 // class java/lang/Integer
46: invokevirtual #11 // Method java/lang/Integer.toString:()Ljava/lang/String;
49: invokevirtual #12 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
52: return
你可以在这里看到,JVM实际需要转换为整数的唯一时间是#43(checkcast)。这样就可以invokevirtual Integer.toString()
。
对println
(#33)的调用不需要演员,因为println
需要Object
,而不是Integer
(也许您以为是在调用{{} 1}},但你不是)。所以JVM永远不需要检查它是否为整数,因为它不需要。
如果您调用了接受println(int)
的方法,而不是致电println(Object)
,则应该看到Integer
。
例如,这个:
ClassCastException
将表演演员:
...
print(intBox.getT());
}
private static void print(Integer integer) {
System.out.println(integer);
}
答案 1 :(得分:1)
类型擦除是原因。在运行时,所有Box实例都相同,它们都包含引用。泛型只对程序员有益,可以传达类型信息并保持您的程序输入良好。
答案 2 :(得分:0)
这就是编译器警告您不要使用非泛型类引用的原因。在运行时,它无法知道intbox的类型,因为泛型不会保存在字节码中。