我无法弄清楚为什么我的Java代码中没有错误。我有一个使用泛型类型的类:
import java.util.*; // For ArrayList
public class Hat<T>
{
public ArrayList<T> convert(String s)
{
T t = (T) s; // Cast happens here
ArrayList<T> list = new ArrayList<T>();
list.add(t);
return list;
}
}
然后,我执行一些我认为应该创建错误的代码:
Hat<Integer> h = new Hat<Integer>();
ArrayList<Integer> iList = h.convert("hello");
这样做会创建一个整数的ArrayList,它以某种方式将String作为元素!这不会在运行时抛出任何错误,即使您打印ArrayList(它打印&#34; [hello]&#34;)。
我希望从&#34;转换&#34;中抛出错误。方法。为什么这不会发生,是否有可能实现?有趣的是,当我尝试将元素从ArrayList作为Integer返回时,会发生这种情况,但错误并非来自&#34; convert&#34;方法
答案 0 :(得分:3)
在Java中,泛型仅在编译时使用;在类型检查器验证程序并且对程序的执行没有影响之后,它们被“擦除”。特别是,在运行时,ArrayList<Integer>
和ArrayList<String>
(或其他任何事件的ArrayList
之间没有区别。完成类型检查后,程序将被删除,执行的程序相当于:
public class Hat
{
public ArrayList convert(String s)
{
Object t = s;
ArrayList list = new ArrayList();
list.add(t);
return list;
}
}
Hat h = new Hat();
ArrayList iList = h.convert("hello");
的行为与你观察到的一样。
所以问题是,为什么这个程序在显然产生一个声称是ArrayList<Integer>
但包含字符串的错误值时会进行类型检查?类型系统不应该拒绝这样的程序吗?
嗯,确实如此,除了有一个很大的漏洞:未经检查的演员阵容。当您对涉及泛型的类型执行强制转换时 - 在您的情况下,行T t = (T) s;
- Java在运行时没有任何内容可用于测试强制转换是否有效,因为擦除。 Java设计者可能刚刚禁止这种转换,在这种情况下你的程序将无法编译。
ArrayList<Integer>
结束。因此,为了警告您需要小心,他们有编译器
但是每当你写这样一个演员时发出一个“未经检查的演员”警告,提醒你有一个可疑的演员,你应该证明这是正确的。在我已经使用的代码库中,未经检查的强制转换需要使用@SuppressWarning
注释,并且注释描述为什么强制转换始终有效。
那么,如果你希望处理未经检查的强制转换并且你宁愿发出运行时检查呢?在这种情况下,您将不得不自己编写运行时检查。您通常可以使用Class
个对象执行此操作。在您的情况下,您可以在Class
构造函数中添加额外的Hat
参数,以表示您期望T
的类,并使用它来进行在运行时检查的类型安全转换:
public class Hat<T>
{
private final Class<? extends T> expectedClass;
public Hat(Class<? extends T> expectedClass)
{
this.expectedClass = expectedClass;
}
public ArrayList<T> convert(String s)
{
T t = expectedClass.cast(s); // This cast will fail at runtime if T isn't String
ArrayList<T> list = new ArrayList<T>();
list.add(t);
return list;
}
}
然后您的呼叫站点需要更改为:
Hat<Integer> h = new Hat<Integer>(Integer.class);
ArrayList<Integer> iList = h.convert("hello"); // throws