2011-10-03 29 views
4
/*1.*/ List l = new ArrayList<Number>(); 
/*2.*/ List<String> ls = l;  // unchecked warning 
/*3.*/ l.add(0, new Integer(42)); // another unchecked warning 
/*4.*/ String s = ls.get(0); 

如果线2和3产生未检查的警告,那么为什么不四号线产生一个未经检查的警告,因为编译器不知道什么是“LS”是指(List<String>List<Integer>)。为什么第4行不生成未经检查的异常?

(注:从OP的原帖编辑来作出推测预期的代码显示 - 特别是包括List<E>类型参数无处不在)

回答

8

编译器认为ls将真正参考的列表字符串 - 如果尚未进行危险操作 - 即第2行,则第4行将是“安全的”(在类型安全方面)。

在没有涉及其他警告的情况下,List<String>应始终指向列表只包含对字符串的引用(或null)。但是,如果您已经破坏了类型安全性,则所有投注都将关闭(除了虚拟机在执行时会捕获这些类型违规)。

该警告显示哪些行是危险的 - 在这种情况下,您正在使用原始类型的地方,即您在说,“好的,我们在这里有一个列表,我不知道里面有什么它虽然。“

4号线不是指原始类型的任何变量 - 它仅是指在List<String>调用get,返回值分配给String变量。如果您认为这应该会产生警告,请显示Java语言规范的哪一部分建议警告是适当的 - 我认为您会发现很难这样做。

3

4号线不产生编译时警告由于ls类型是List<String>这意味着它的get方法返回Stringnull。任何违规行为将在编译时被捕获并将导致ClassCastException

编辑:

有许多的东西,编译器知道有关字节码校验器和解释器没有。

  1. 泛型类型
  2. 编译时只标注
  3. checked异常
  4. 外一流的士兵

Java编译器知道这些事情,所以在使用它们指出错误,但字节码验证程序和解释程序不会在生成解释程序文件的部分时“擦除”它们。

所以在编译的步骤

  1. 查找通过查找.java.class文件所需的所有类。
  2. 确保所有类型都检查。
  3. 清除解释器不需要的信息(但在javac被其输入CLASSPATH上的.class调用时将其隐藏起来)。
  4. 生成输出.class文件。
+0

但是列表将在类型擦除期间创建List。但编译器如何知道? – Rekha

+0

但是在列表擦除过程中将列出列表。但是编译器如何知道? – Rekha

+0

由于类型删除在编译期间发生,即编译器在删除之前检查签名。 – meriton

1

因为ls被声明为List<String> 4号线不给予警告,对ls.get(0)返回一个字符串(至于编译器知道),而你将其分配给变量字符串s

对于编译器来说,一切都看起来是正确的 - 它没有看到你“非法”指向List<Integer>的事实。

但是,您将得到一个ClassCastException是运行时

0

4号线绝对没问题。你可能会想你的代码是:

String s = l.get(0); // this will not compile without the cast 
0

4号线不保证一个未检查的警告,因为它不引入类型错误的可能性。 ls的声明表示它是List<String>,而List<String>包含String s。它不是一种称为heap pollution的病态情况,只有在未检查警告被错误抑制时才会出现,但这不是第4行的错误。

但是,第4行在运行时会出现ClassCastException,因为编译器是意识到堆污染的可能性,并发出一个额外的强制转换,以在调用其上的方法之前验证返回的对象是否属于正确的类型。

相关问题