tags:

views:

1709

answers:

6

Why is it not legal to have those two methods in the same class?

class Test{
   void add(Set<Integer> ii){}
   void add(Set<String> ss){}
}

I get the complication error "Method add(Set) has the same erasure add(Set) as another method in type Test". while I can work around it, I was wondering why javac doesn't like this.

I can see that in many cases, the logic of those two methods would be very similar and could be replaced by a single

public void add(Set<?> set){}

Method, but this is not always the case.

This is extra annoying if you want to have two constructors that takes those arguments because then you can't just change the name of one of the constructors.

+15  A: 

Java generics uses type erasure. The bit in the angle brackets (<Integer> and <String>) gets removed, so you'd end up with two methods that have an identical signature (the add(Set) you see in the error). That's not allowed because the runtime wouldn't know which to use for each case.

If Java ever gets reified generics, then you could do this, but that's probably unlikely now.

GaryF
I am sorry but your answer (and the other answers) do not explain why there is an error here. Overload resolution is done at compile time and the compiler surely has the type information needed to decide which method to link by address or by whatever the method is referenced in bytecode which I believe is not signature. I even think some compilers will allow this to compile.
Stilgar
A: 

It could be possible that the compiler translates Set(Integer) to Set(Object) in java byte code. If this is the case, Set(Integer) would be used only at compile phase for syntax checking.

rossoft
It's technically just the raw type `Set`. Generics don't exist in byte code, they're syntactic sugar for casting and provide compile-time type safety.
Andrzej Doyle
+8  A: 

This is because Java Generics are implemented with Type Erasure.

Your methods would be translated, at compile time, to something like:

void add(Set ii) {
    Iterator it = ii.iterator();
    while (it.hasNext()) {
        int i = ((Integer)it.next()).intValue();
        // ...
    }
}

void add(Set ss) {
    Iterator it = ss.iterator();
    while (it.hasNext()) {
        String s = ((String)it.next()).substring(2,4);
        // ...
    }
}

Both translated methods have the same signature hence the error.

bruno conde
+5  A: 

The problem is that Set<Integer> and Set<String> are actually treated as a Set from the JVM. Selecting a type for the Set (String or Integer in your case) is only syntactic sugar used by the compiler. The JVM can't distinguish between Set<String> and Set<Integer>.

kgiannakakis
A: 

Would it not be possible to only have one method, but use the instanceof keyword in some way to choose which what to do with the set?

Krigath
No it would not - because generics are implemented via erasure, there is no such thing as an **object** of type `List<Integer>`. You can test for `instanceof List`, but you can't check the generic type as this exists only on *references* to the object. Since the object itself would simply be a (genericless) `List`, you can't use instanceof to determine between the cases (in face this won't even compile).
Andrzej Doyle
A: 
sateesh