Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Consider this trivial problem:</p> <pre><code>class A { static void foo(){ } } class B extends A { static void foo(){ } } void test() { A.foo(); B.foo(); } </code></pre> <p>Suppose we remove the <code>foo</code> method from <code>B</code>, and we only recompile <code>B</code> itself, what could happen when we run <code>test()</code>? Should it throw linkage error because <code>B.foo()</code> is no found? </p> <p>According to JLS3 #13.4.12, removing <code>B.foo</code> doesn't break binary compatibility, because <code>A.foo</code> is still defined. This means, when <code>B.foo()</code> is executed, <code>A.foo()</code> is invoked. Remember, there's no recompilation of <code>test()</code>, so this forwarding must be handled by JVM.</p> <p>Conversely, let's remove <code>foo</code> method from <code>B</code>, and recompile all. Even though compiler knows statically that <code>B.foo()</code> actually means <code>A.foo()</code>, it still generate <code>B.foo()</code> in the bytecode. For now, JVM will forward <code>B.foo()</code> to <code>A.foo()</code>. But if in future <code>B</code> gains a new <code>foo</code> method, the new method will be invoked at runtime, even if <code>test()</code> isn't recompiled.</p> <p>In this sense, there is a overriding relation among static methods. When compile sees <code>B.foo()</code>, it must compile it to <code>B.foo()</code> in bytecode, regardless whether <code>B</code> has a <code>foo()</code> today.</p> <p>In your example, when compiler sees <code>BigCage.printList(animalCage)</code>, it correctly infer that it's actually calling <code>Cage.printList(List&lt;?&gt;)</code>. So it needs to compile the call into bytecode as <code>BigCage.printList(List&lt;?&gt;)</code> - the target class must be <code>BigCage</code> here instead of <code>Cage</code>.</p> <p>Oops! Bytecode format hasn't been upgrade to handle method signature like that. Generics information are preserved in bytecode as auxilary information, but for method invocation, it's the old way. </p> <p>Erasure happens. The call is actually compiled into <code>BigCage.printList(List)</code>. Too bad <code>BigCage</code> also has a <code>printList(List)</code> after erasure. At runtime, that method is invoked!</p> <p>This problem is due to the mismatch between Java spec and JVM spec. </p> <p>Java 7 tightens up a little; realizing bytecode and JVM can't handle such situations, it no longer compiles your code:</p> <blockquote> <p>error: name clash: printList(List) in BigCage and printList(List) in Cage have the same erasure, yet neither hides the other</p> </blockquote> <p>Another fun fact: if the two methods have different return types, your program will work correctly. This is because in byte code, method signature includes return type. So there is no confusion between <code>Dog printList(List)</code> and <code>Object printList(List)</code>. See also <a href="https://stackoverflow.com/questions/5527235/type-erasure-and-overloading-in-java-why-does-this-work/5528802#5528802">Type Erasure and Overloading in Java: Why does this work?</a> This trick is only allowed in Java 6. Java 7 forbids it, probably for reasons other than technical ones.</p>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
    1. COSo if I follow correctly, the compiler is adding a `BigCage.printList(List<?>)` to **class BigCage** since **class Cage** has a `printList(List<?>)` defined and **BigCage** extends **Cage**. I guess my only follow up question then is why can't I manually add `printList(List<?>)` to **class BigCage** without a compile time error (note 6)? Would it not be possible for the compiler to see that one of the static methods in **BigCage** has a type erasure identical to one of the base class and generate an error?
      singulars
    2. COtwo separated methods in 2 classes. can't put them in one class. see http://stackoverflow.com/questions/5527235/type-erasure-and-overloading-in-java-why-does-this-work/5528802#5528802 javac6 is unable to stuff two methods with same bytecode signature in one class
      singulars
    3. COI apologize if I'm still missing something obvious. I still don't understand why I get a compiler error if I change the method `void <U extends Dog> printList(List<U>)` in **BigCage** to `void <U> printList(List<U>)` (Note 3). Doesn't `void <U extends Dog> printList(List<U>)` and `void <U extends Dog> printList(List<U>)` both result in the same erasure? Why does U extending anything result in the error going away when without the extension we get one? I get that the JVM can't properly pick which overloaded method to select, but can't the compiler check for this condition and generate an error?
      singulars
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload