问题
See below simple snippet:
public class GenericsOverloadingDistinguish<T> {
public void print1(T t) {
System.out.println("t");
}
public void print1(Integer i) {
System.out.println("integer");
}
}
public static void main(String[] args) {
new GenericsOverloadingDistinguish<Integer>().print1(new Integer(1));
}
This would cause an ambiguous method call and will not compile.
This is utterly confusing on the user of that class. It is not able to call neither print1(T t)
nor print1(Integer i)
simple because it unfortunately used Integer
as the generic type.
I understand generics is compile-time and there is type erasure, but doesn't Java have something to prevent such errors?
What if the GenericsOverloadingDistinguish
Class is given and can't be changed, and I just need to invoke print1(T t)
with T
being an Integer?
回答1:
If the class is given, you're out of luck, there are no nice ways to resolve the problem.
How would you guess which method the designer expected to be called in this case? You simply can't. Now think of how the compiler could do the job?
What could've been done in the language is to not allow this kind of overloading at all if the type parameter can be given a conflicting value. Why it hasn't been done is a good question but difficult to answer. It was probably deemed too restrictive.
Anyway, if you absolutely must, you can work around this problem like this:
GenericsOverloadingDistinguish<Integer> t = new GenericsOverloadingDistinguish<Integer>();
((GenericsOverloadingDistinguish)t).print1((Object)new Integer(1)); //prints "t"
((GenericsOverloadingDistinguish)t).print1(new Integer(1)); //prints "integer"
This works, because the type erasure of print1(T)
is print1(Object)
.
Needless to say, this is bug ugly, and you really shouldn't be using raw types, but this is the least messy way of dealing with a bad situation.
回答2:
You can actually avoid this by doing:
public class GenericsOverloadingDistinguish<T> {
public void print1(T t) {
if (t instanceof Integer)
System.out.println("integer");
else System.out.println("t");
}
}
public static void main(String[] args) {
new GenericsOverloadingDistinguish<Integer>().print1(new Integer(1));
}
If your code is as-is and cannot be changed, then you're in a problem, since there is no clean (imo) way to distinguish if T
or Integer
overloaded method should be called.
来源:https://stackoverflow.com/questions/35104399/overloading-a-method-which-takes-in-generic-type-causes-ambiguous-method-call-co