Java 8 generic function should be ambiguous, but failing in runtime

断了今生、忘了曾经 提交于 2019-12-03 00:28:03
Todd Sewell

The compiler error

In the first case, the method getString is required to return a Comparable instance. The compiler looks for overloads of the func method, and it finds only one that can accept a Comparable: func(Comparable ... input). Map doesn't implement that interface, so the second overload is not applicable. There is no ambiguity.

In the second case, getString can return anything. Both overloads work, so there is an ambiguity. Note though, the cast to T is unsafe/wrong in both cases.

The usafe cast

The kind of generic method you've written basically tells the compiler "I can return an instance of any class you want that implements Comparable". You can't actually keep this promise though.

Lets say I have the following code:

String str = getString();
Integer num = getString();

This code will compile, both String and Integer implement the Comparable interface. The second line will fail at runtime though: the code tries to cast a String to an Integer.

Your second case is also wrong for the same reason I explained above. It promises it can return any type you want. It obiously can't keep that promise too (Runnable here is a random example, it could be anything):

Runnable run = getString()

Your updated code

The compiler sees two possible overloads that both match, func(Comparable...input) and func(ComparableMap <?,?> m). It prefers the second one, because varargs methods are always chosen last (for compatebility reasons). All of this is corect behaviour.

The code then throws the ClassCastException because your getString method doesn't keep it promise (letting the caller decide what kind of Comparable to return).

How to fix it?

The fundamental problem is that your getString method makes a false promise. As such, I don't really know what that code tries to accomplish. If you can elaborate we may be able to help you furter.

Yeah, I have no idea why Java 8 is choosing the overload that takes a map over the one that takes the Comparable vararg. I'm going to guess that good old type erasure is at play here.

That said, I would just make getString() return a Comparable rather than a T.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!