Win a copy of Programmer's Guide to Java SE 8 Oracle Certified Associate (OCA) this week in the OCAJP forum!
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic

Question on type erasure. (just another generics question)

 
Florin Florentin
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hello. I have a question about overloading / type erasure.

The following code compile and runs. I think (that's only my opinion, so if i'm not right i would love to be corrected) because T it's erased in the second function to String, and in the first it is erased to Object, so there are different arguments.




The following code isn't compiling. It's saying that the methods have the same erasure t1(List<T>).



Why is in the list example a different behavior?
 
Chad Michaels
Ranch Hand
Posts: 42
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Interesting. I have no idea, but I'd like to guess.

I think it's basically because in one example, both parameters are different:
public <T> void t1(T t1) { } // T can be any object
public <T extends String> void t1(T t2){ } // T can only be String, or a subclass

And, in the other example which causes a compiler error, both parameters are the same:
public <T> void t1(List<T> t1) { } // One list parameter
public <T extends String> void t1(List<T> t2) { } One list parameter

In fact, you get the same compiler error by just:
public void t2( List< String > x ) { }
public void t2( List< Integer > x ) { }

Again, that's just a guess, and I'm probably wrong. You're probably right, it has something to do with erasure. I would like to know the correct answer myself.
 
Florin Florentin
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I would like more opinions
 
Dieter Quickfend
Bartender
Posts: 543
4
Java Netbeans IDE Redhat
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
<T extends String> can only be a String. Don't forget String is final. So for Strings, it will use that method. For anything else, it will use another.

As before said, the List parameter is the same parameter. List<Integer> and List<String> is both the same class, so it's not a legal overload.
 
Wouter Oet
Saloon Keeper
Posts: 2700
IntelliJ IDE Opera
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It doesn't matter that in the example String was used. It can be replaced with (almost) everything.

The first part is compiled to:
public void t1(java.lang.Object);
Code:
0: return

public void t1(java.lang.String);
Code:
0: return

The second part will not compile because of the name clash due to type erasure. The type erasure will (simply put) convert the methods to something like this:
public void t1(List) { }
public void t1(List){ }
 
Florin Florentin
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Thank you for the answer.

Wouter Oet wrote:

The second part will not compile because of the name clash due to type erasure. The type erasure will (simply put) convert the methods to something like this:
public void t1(List) { }
public void t1(List){ }



Why doesn't it is compiled to :

public void t1(List<java.lang.Object>) { }
public void t1(List<java.lang.String>){ }

?
 
Yves Caron
Greenhorn
Posts: 3
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Why doesn't it is compiled to :

public void t1(List<java.lang.Object>) { }
public void t1(List<java.lang.String>){ }

?


Consider this first example:



Before the compiler erases the type information, List<Object> and List<Number> are two different types and the compiler will force you to use the correct type.

After the compiler has done all of its verifications, it erases the type information.

After the compiler erased the type information, List<Object> and List<Number> both become the same type which is List.

Both methods end up with the same signature:
public void t2(List objects) { }
public void t2(List numbers) { }

The result is a name clash.

Compare this with the second example:



You can substitute any type whatsoever, in the end, the compiler will erase it and the type will be List just as it did in the first example.

Here is a last example:



Now compare the methods t1 from Example02 and Example03. The compiler does not find a name clash but it reports that <O>t1(O) is already defined. You can only conclude that <O>t1(O) and <N extends Number>t1(N) are two different method signatures. From your comments, you had already understood that part.

Take care.
 
Florin Florentin
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Sorry for the late response. I was away a couple of days.

Thank you for your answers, but i want to know why it's this behaviour.
 
Dieter Quickfend
Bartender
Posts: 543
4
Java Netbeans IDE Redhat
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
It's all about the method signature. In the first example, it's a legal overload, because basically, <T extends Object> is not the same as <T extends String>. The compiler will know which method to use, namely the second if it's a String, the first if it's anything other than a String.

In the second example, with the Lists, because lists have no type at Runtime, you're basically calling "public void t1(List t2){}" twice, which is the same method signature at runtime and not a legal overload.

 
Florin Florentin
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Is it then correct to afirm that when using generics, type information is erased to it's first bound, except list, where type information is erased to the raw type?

 
Shanky Sohar
Ranch Hand
Posts: 1051
Eclipse IDE Firefox Browser
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
PLease keep this in mind that all the generics type information is erased at compile time
So at runtime collection are collection like earlier days
 
Dieter Quickfend
Bartender
Posts: 543
4
Java Netbeans IDE Redhat
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Florin Florentin wrote:Is it then correct to afirm that when using generics, type information is erased to it's first bound, except list, where type information is erased to the raw type?

Something like that, I believe.

In the second case with the Lists, the signature the method will use is determined, type will be erased, and at runtime, the signature will be called but there will be two methods with the same identical signature in that class. So I'd say since the compiler needs to be certain about generics due to type erasure, it won't allow two methods which will resolve to the same signature at runtime, because even though the signature the program will use is determined at compile time, the actual method will be called only at runtime (see overriding/overloading), which would compromise type safety.


However, I think I'll go dig a little deeper into Generics again.

Good question!
 
  • Post Reply
  • Bookmark Topic Watch Topic
  • New Topic