<< Innovation Through Polls Considered Meaningless | Home | Java Generics: Let The Other Shoe Drop >>

Thursday Java Generics Quiz

I'm going through O'Reilly's Java Generics and Collections by Maurice Naftalin and Philip Wadler to gain the necessary understanding of Java generics to effectively use it. I mentioned this book 53 days ago.

Here's something that surprised me. Can you guess if the following two classes will compile? And why?

import java.util.*;
class Foo {
  public Integer foo(List list) {
   return null;
  }
  public String foo(List list) {
    return null;
  }
}
import java.util.*;
class Bar {
  public Integer bar(List<Integer> integers) {
    return null;
  }
  public String bar(List<String> strings) {
    return null;
  }
}
Tags :


Re: Thursday Java Generics Quiz

I'll be honest and guess BEFORE I try it out. I say no, they will not compile. In your first class, you have two methods with the same arguments; you cannot overload simply by changing the return type. In the second example, erasure removes the type information, so you are in the same boat. Neither compiles.

Re: Thursday Java Generics Quiz

Well, I'm wrong. Bar compiles. I don't know why.

Re: Thursday Java Generics Quiz

Generic information is preserved in classes and methods, but not in objects. Local variable types are never preserved (but can be partially inferred from bytecode). Therefore erasure isn't happening here.

If you try to call bar(new ArrayList()), that is ambiguous.

Re: Thursday Java Generics Quiz

I knew I should have checked before submitting..

If you make the return types the same then the methods have the same erasure as each other. With differing return types the methods will (I think) get different generated names to each other.

I'm glad I don't overload methods!

Re: Thursday Java Generics Quiz

Here's the book's explanation (the books example method name is sum):

Here are the erasures of the signatures of the two methods
int sum(List)
String sum(List)
The two methods have different return types, which is sufficient for Java to distinguish them.

I can't say I understand why.

Re: Thursday Java Generics Quiz

Not sure I understand that explanation either. It's legal to call a method for the side effect, eg, foo(new Vector()), hence Foo is ambiguous. I think that Foo won't compile, but Bar will. Erasure is a red herring: method overloading is resolved at compile time.

Re: Thursday Java Generics Quiz

Bar will compile because the methods have distinct signatures and distinct erasures. Foo won't compiler because the two methods have the same signature.

Re: Thursday Java Generics Quiz

Thanks.

So the rules for comparing signatures and the rules for comparing erasures are different. Even through

int sum(List)
String sum(List)
are considered the same as signatures they are considered different as erasures.

Re: Thursday Java Generics Quiz

I obviously need to buy the book, because I just don't get it. After compiling Bar, I ran javap -c to disassemble the code. Both methods looked identical to me. I assume there must be something in the bytecode that makes the methods different. This is too hard. Sigh.

Re: Thursday Java Generics Quiz

if you're still this confused after reading the book i'd say it didn't do a good job explaining it.

Neil's comment didn't exactly clear everything up either, imho.

Re: Thursday Java Generics Quiz

Well, I usually have to think hard about Neal's responses, but this one looks clear enough to me. To be compiled, the methods have to have distinct signatures *and* distinct erasures. The signatures of the Bar methods are different, obviously, but those of the Foo methods aren't, so Foo doesn't compile. The erasure of the Bar methods leaves them with different return types, so Bar fulfils both requirements.

Re: Thursday Java Generics Quiz

In Java Generics section 3.8 last paragraph explains this. The class file has the capability to have multiple functions with the same signature, but it is not allowed in Java source. If it would have been allowed then there may be ambiguous situations for the compiler to figure out which method to invoke. Whereas with Generics , compiler has better means of detecting which method to invoke.

Add a comment Send a TrackBack