tags:

views:

67

answers:

4

I stumbled upon an interesting error that I've never seen before, and can't explain why

Consider the following class

public class Sandbox<A,B> {
 public void put(B b) {
 }
 public void put(A a) {
 }
}

Looks okay to my eyes. So I compile it and then get this

name clash: put(B) and put(A) have the same erasure

Huh? How do two different generic types have the same signature? There completely separate!

I'm probably missing something completly basic, but I've just not run into this issue before. I've band-aid fixed the problem by calling the methods putA and putB, but I'm really curious to why this error happened in the first place.

Would someone mind explaining?

+8  A: 

Logically, consider the following code:

SandBox<String, String> sandBox = new SandBox<String, String>();
sandBox.put("foo"); // which put is invoked?

(Although I should admit that it's possible to produce perfectly valid code that produces similar situations - and then a method is chosen at "random".)

Formally, I think this section of the JLS is relevant. Both versions of put have the same argument types - if I read that section correctly.

waxwing
I like this counter example very much -- makes it a lot clearer than the other answers that go into detail about generics being implemented via erasure. However, it doesn't explain why the similar declaration of the class 'SandBox<A extends Number,B extends CharSequence>' leads to the same compilation error.
Matt McHenry
+2  A: 

Generics in Java are only available at code level and not at runtime.

So when the compiler translates your sourcecode, the types you specified for A and B are "erased". This means both types are set to java.lang.Object.

So you end up with two identical method signatures.

Johannes Wachter
Not relevant in this case. It doesn't make sense even if you could overload on non-erased types. And being able to overload with matching erased types could be done without reification.
Tom Hawtin - tackline
+1  A: 

How do two different generic types have the same signature? There completely separate!

Java generics are based on type erasure. That means your code basically compiles to this:

public class Sandbox{
 public void put(Object b) {
 }
 public void put(Object a) {
 }
}
Michael Borgwardt
As Johannes, irrelevant.
Tom Hawtin - tackline
+1  A: 

Huh? How do two different generic types have the same signature? There completely separate!

The root of your problem appears to be that you do not have a good grasp of Java terminology.

The compiler is not telling you that two generic types have the same signature:

  • Types (generic or otherwise) don't have signatures in the formal sense. Methods have signatures.

  • A and B are not generic types. They are type parameters.

  • The things that the compiler tells you have the same signature are put(A) and put(B). These are methods, not types.

EDIT

OK ... so you do understand the terminology.

If you use technical terminology incorrectly, don't be surprised if:

  • some people misinterpret your questions (and answers),
  • some people call you out for using terminology incorrectly, and
  • some people discount what you ask / say as being uninformed.

But the case I'm worried most about (and the real reason I took the time to answer your question!!) is when some poor confused Java newbie does a Google search, finds your SO question full of sloppy terminology, and gets even more confused.

Stephen C
Sorry, I wasn't thinking clearly at the time. By signatures I meant method signatures. Eg `public void stuff()`. And I randomly picked generic types since it sounded correct. As you can see, I'm not the person that quotes terms from the JLS
TheLQ