简体   繁体   English

为什么第4行不生成未经检查的异常?

[英]Why doesn't line 4 generate an unchecked exception?

/*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);

If the lines 2 and 3 produce an unchecked warning then why doesn't the 4th line generate a unchecked warning since compiler does not know what 'ls' is referring to ( List<String> or List<Integer> ). 如果第2行和第3行产生未经检查的警告,那么为什么第4行不会生成未经检查的警告,因为编译器不知道'ls'指的是什么( List<String>List<Integer> )。

(Note: edited from the OP's original post to make the code display as presumably intended - notably include the type parameters for List<E> everywhere.) (注意:从OP的原始帖子进行编辑,以使代码显示为可能的 - 特别是包含List<E>的类型参数。)

The compiler thinks that ls will genuinely refer to a list of strings - line 4 would be "safe" (in terms of type safety) if there hadn't already been dangerous operations - namely line 2. 编译器认为 ls将真正引用字符串列表 - 如果尚未进行危险操作,则第4行将是“安全的”(就类型安全而言) - 即第2行。

With no other warnings involved, a List<String> should always end referring to a list which only contains references to strings (or null). 如果不涉及其他警告, List<String>应始终引用仅包含对字符串(或null)的引用的列表。 But if you've already broken type safety, all bets are off (other than that the VM will catch those type violations at execution time). 但是如果你已经打破了类型安全性,那么所有的赌注都是关闭的(除了VM将在执行时捕获那些类型的违规)。

The warning shows which lines are dangerous - in this case, places where you're using a raw type, ie you're saying, "Well, we've got a list here. I've no idea what's in it though." 警告显示哪条线是危险的 - 在这种情况下,你正在使用原始类型的地方,即你说,“好吧,我们这里有一个清单。我不知道它里面有什么。”

Line 4 doesn't refer to any variables of raw types - it only refers to calling get on a List<String> , and assigning the return value to a String variable. 4号线不是指原始类型的任何变量-它是指调用getList<String> ,并指派返回值的String变量。 If you think this should produce a warning, please show which section of the Java Language Specification suggests that a warning is appropriate - I think you'll find it hard to do so. 如果您认为这应该产生警告,请显示Java语言规范的哪一部分建议警告是适当的 - 我认为您会发现很难这样做。

Line 4 produces no compile-time warning because the type of ls is List<String> which means its get methods returns a String or null . 第4行不产生编译时警告,因为ls的类型是List<String> ,这意味着它的get方法返回Stringnull Any violation will be caught at compile time and will result in a ClassCastException . 任何违规都将在编译时捕获并导致ClassCastException

EDIT: 编辑:

There are a number of things that the compiler knows about that the bytecode verifier and interpreter do not. 编译器知道有许多事情,字节码验证器和解释器没有。

  1. generic types 通用类型
  2. compile-time-only annotations 仅编译时注释
  3. checked exceptions 检查异常
  4. outer-class privates 外层私人

The java compiler knows about these things and so points out errors in their use, but the bytecode verifier and interpreter do not so it "erases" them when producing the portion of the .class file meant for the interpreter. java编译器知道这些事情并因此指出它们的使用中的错误,但是字节码验证器和解释器不这样做,因此它在生成用于解释器的.class文件部分时“擦除”它们。

So the steps in compilation are 所以编译的步骤是

  1. Look for all the classes needed by looking for .java and .class files. 通过查找.java.class文件来查找所需的所有类。
  2. Make sure everything type checks. 确保所有类型检查。
  3. Erase information not needed by the interpreter (but hide it awway in case javac gets called with the .class on its input CLASSPATH). 擦除解释器不需要的信息(但是如果在其输入CLASSPATH上使用.class调用javac,则将其隐藏起来)。
  4. Produce the output .class files. 生成输出.class文件。

Line 4 doesn't give a warning because ls is declared as a List<String> , the ls.get(0) returns a String (as far as the compiler knows), and you're assigning it to a String variable s 第4行没有给出警告,因为ls被声明为List<String>ls.get(0)返回一个String(就编译器所知),并且你将它分配给一个String变量s

To the compiler, everything looks correct - it does not look at the fact that you "illegally" pointed it at a List<Integer> . 对于编译器来说,一切看起来都是正确的 - 它没有看到你“非法”将它指向List<Integer>的事实。

You will, however, get a ClassCastException are runtime . 但是,您将获得ClassCastException 运行时

Line 4 is absolutely fine. 第4行绝对没问题。 You are probably thinking your code is : 您可能认为您的代码是:

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

Line 4 does not warrant an unchecked warning, as it does not introduce the potential of type errors. 第4行不保证未经检查的警告,因为它不会引入类型错误的可能性。 The declaration of ls says it's a List<String> , and List<String> contain String s. ls的声明表示它是List<String> ,而List<String>包含String That it does not is a pathological situation called heap pollution that can arise only if unchecked warnings are incorrectly suppressed, but that's not the fault of line 4. 它不是一种称为堆污染的病态情况,只有在未经检查的警告被错误地抑制时才会出现,但这不是第4行的错误。

Line 4 does, however, throw a ClassCastException at runtime, as the compiler is aware of the possiblity of heap pollution , and emits an additional cast to verify that the returned object is of the proper type before invoking methods on it. 但是,第4 ClassCastException运行时抛出ClassCastException ,因为编译器知道堆污染的可能性,并在调用其上的方法之前发出额外的强制转换来验证返回的对象是否是正确的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM