Question on type erasure. (just another generics question)

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>).

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

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){ }

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){ }

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

Joined: May 12, 2009
Posts: 43

posted Aug 24, 2010 06:32:13

0

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.

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

Joined: May 12, 2009
Posts: 43

posted Aug 24, 2010 12:49:25

0

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?

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.