Java name clash, have the same erasure, neither hides the other
Asked Answered
G

3

17

I am getting this name clash error and i don't know how should i solve the problem. I have two classes and i am using overloaded method "createSensors". To simplify here is the code that generates the problem:

public abstract class ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassA> list) {
        List<Sensor> sensors = new ArrayList<Sensor>();
        for (ClassA s : list) {
           sensors.add(s.getSensor());
        }
        return sensors;
    }
}

public abstract class ClassB extends ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassB> list) {
        List<Sensor> sensors = new ArrayList<Sensor>();
        for (ClassB s : list) {
           sensors.add(s.getSensor());
        }
        return sensors;
   }
}
Ghiselin answered 22/12, 2012 at 12:47 Comment(3)
It looks to me like you don't even need two methods, since they do exactly the same thing.Phagocytosis
methods use different dataGhiselin
but all they use is the getSensor() method, which (if it isn't already) could be inherited or part of an interface, to eliminate the duplicate code. That would be much better even if the collision weren't an issue.Phagocytosis
R
5

The general solution is to use different names. These methods could be in classes without an inheritance relationship as these are not instance methods.

As pointed out, the method implementation in the question are the same (typo excepted).

(This issue with overloading is often confused with erasure of runtime types. Overloading is a link-time rather than a dynamic issue, so could be easily fixed in the language. It's just not a particularly useful change, and not a good idea to encourage overloading.)

Rhymester answered 22/12, 2012 at 13:42 Comment(2)
Lets assume that those two implementations were having radically different behaviours, you'd still get this error. It would be nice to focus on the essence of the question rather than on the specifics of the example ;)Porkpie
@Porkpie I think the essential answer is to use different names. But very often generics are thought to be necessary where they actually aren't as in this case, so it is useful to point that out.Bukharin
P
12

General answer :

Apart from the problem of the same implementation here, the core of the problem is that, somewhat barbaric, "method A and Method B have the same erasure".

What makes it a complicated question is that we generally don't (at least I did not this very morning) know a lot about "Type Erasure".

To make it short :

Parametric types perform type check at compile time (to ensure type correctness) but forget their type parameters at runtime (to avoid the generation of underlying methods).

This sounds at the same time simple and puzzling. Best way to understand it is to refer to the following literature :

  1. What is a reifiable type ?
  2. How and under what conditions is erasure performed ?
  3. Have you any idea/examples about what it could imply in my coding life ?
  4. Well that's odd and I don't really like it but I'm curious why they did that ...

Hope that'll help you as much as it helped me.

Specific answer :

In your case

public abstract class ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassA> list) {
        //do stuff
    }
}

public abstract class ClassB extends ClassA {
    public static List<Sensor> createSensors(Collection<? extends ClassB> list) {
        //do other stuff
   }
}

will be "transformed" by javac to

public abstract class ClassA {
    public static List createSensors(Collection list) {
        //do stuff
    }
}

public abstract class ClassB extends ClassA {
    public static List createSensors(Collection list) {
        //do other stuff
   }
}

where one clearly can't override the other (not the same type parameter) but end up being exactly the same at runtime (no way for your program to choose which one to use).

Enough of this problem, how to solve it ? You may proceed with one of the following approach :

  • Use different names : createASensors and createBSensors this approach is the most obvious but would seem a little less elegant.

  • Add a parameter : createSensors(Collection<? extends ClassA> list, ClassA typeDefiner) this approach can seem barbaric but is a little less elegant but is the one used in java.util.List for the method <T> T[] toArray(T[] a).

Porkpie answered 26/12, 2013 at 17:9 Comment(4)
Erasure (knowledge of which in general is assumed by the question title) of runtime types is not relevant to this question, as it is about link-time method selection. / That toArray method predates generics by three releases.Rhymester
Your answer explains it very well. But I was wondering if you could also explain why the compile behaves like this, and why we are not simply allowed to call the methods by their actual class to differentiate them; ClassA.createSensors(...) ClassB.createSensors(...)Ewell
"but is the one used in java.util.List for the method <T> T[] toArray(T[] a)"; It has the parameter to allow directly placing the elements in the given array or otherwise using at least the runtime type of the given array, see the docs.Grandee
... with other words ... it should compile just fine!Kibbutznik
R
5

The general solution is to use different names. These methods could be in classes without an inheritance relationship as these are not instance methods.

As pointed out, the method implementation in the question are the same (typo excepted).

(This issue with overloading is often confused with erasure of runtime types. Overloading is a link-time rather than a dynamic issue, so could be easily fixed in the language. It's just not a particularly useful change, and not a good idea to encourage overloading.)

Rhymester answered 22/12, 2012 at 13:42 Comment(2)
Lets assume that those two implementations were having radically different behaviours, you'd still get this error. It would be nice to focus on the essence of the question rather than on the specifics of the example ;)Porkpie
@Porkpie I think the essential answer is to use different names. But very often generics are thought to be necessary where they actually aren't as in this case, so it is useful to point that out.Bukharin
D
-2

Check the project setting and compiler version of the project. Right click on project --> Properties --> Java Compiler. Make sure compliance setting are up to date. I had this problem when compliance settings were set to 1.4 instead 1.6

Dor answered 5/11, 2014 at 9:35 Comment(1)
Compiler settings have nothing to do with this error.Goulden

© 2022 - 2024 — McMap. All rights reserved.