我正在阅读关于泛型的Oracle教程,但无法弄清楚提供的示例有什么问题。 (该教程可以在@ https://docs.oracle.com/javase/tutorial/java/generics/types.html)
找到引用教程:
首先检查对任何类型的对象进行操作的非泛型Box类。它只需要提供两个方法:set,它将一个对象添加到框中,get,它将检索它:
public class Box { private Object object; public void set(Object object) { this.object = object; } public Object get() { return object; } }
由于它的方法接受或返回
Object
,因此只要它不是原始类型之一,您就可以随意传入任何内容。在编译时无法验证类的使用方式。代码的一部分可能会在框中放置一个Integer并期望从中获取Integers,而代码的另一部分可能会错误地传入String
,从而导致运行时错误。“
我试图弄清楚为什么运行时错误是这种操作的结果但是无法提出解释,所以我在我的IDE上重新创建了这种情况,运行了代码,但没有得到任何错误。 这是一个错误吗?我误解了这种情况吗?
以下是我为测试情况而创建的示例代码:
Box类定义
public class Box
{
private Object ob;
public Object getObject(){
return ob;
}
public void setObject(Object ob){
this.ob = ob;
}
}
测试Box类
public class BoxTest
{
public static void run(){
String sPar = "hello";
Integer iPar = 45;
Box box = new Box();
box.setObject(iPar);
System.out.println(box.getObject());
box.setObject(sPar);
System.out.println(box.getObject());
}
}
我也尝试传入一个原始类型,它仍然可以正常运行...那么为什么在这种情况下会发生运行时错误?
答案 0 :(得分:1)
这指的是你可以写:
Box box = new Box();
box.setObject(Integer.valueOf(1));
String value = (String) box.getObject();
此代码编译良好,但在运行时出错。
一般来说,没有办法知道 - 没有测试每种可能的类型 - Box.getObject()
将返回什么类型。
使用演员表可能看起来有点不寻常 - 当然你总会知道你放入盒子里的东西。如果您有一个方法需要Box
参数包含String
,则无法知道:
void doSomethingToStringBox(Box box) {
String value = (String) box.getValue();
}
您可以在代码中的任何位置(至少从可见的位置)调用此方法,因此您无法100%确定编写该代码的人知道Box
必须包含{{ 1}}。
如果正确使用了该类的通用版本:
String
或
Box<Integer> box = new Box<>();
box.setObject(Integer.valueOf(1));
// Compiler error - Integer cannot be cast to String.
String value = (String) box.getObject();
我强调上面的“正确”一词,因为在没有泛型的情况下仍然可以使用通用的Box<String> box = new Box<>();
// Compiler error - Integer cannot be converted to String
box.setObject(Integer.valueOf(1));
String value = box.getObject();
:
Box
然后你回到了与第一个例子相同的类型 - 不安全的情况。
这称为原始类型,您不应在现在编写的任何代码中使用它们。允许它们与遗留代码向后兼容,并且将来可能不受支持。