3

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
  • 2
    I'd guess that if such class exists and is unmodifiable, it is bad design. Commented Jan 30, 2016 at 17:01

2 Answers 2

2

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.

Sign up to request clarification or add additional context in comments.

2 Comments

On a related note, the language does actually disallow overloading where two methods have the same erased type. For example an example, try making print1(Integer i) into print1(Object i). The code will not compile. This makes sure that you aren't absolutely boxed off into a corner where you can't use even the hackiest solution to access the method you want, (since, if print1(Object i) did compile in that example, your casting solution wouldn't be able to distinguish the two methods).
@Kröw Indeed, or you can also try replacing <T> with <T extends Integer>.
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.

2 Comments

There is indeed no clean way, but there's a not too complicated dirty one :)
Haha when I saw your answer i was like "what!" :D

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.