Java 8通用函数应该是不明确的,但是在运行时会失败 [英] Java 8 generic function should be ambiguous, but failing in runtime
问题描述
我试图将Java 7代码迁移到Java 8,所以我的代码类似于:
package test ;
import java.util.Arrays;
import java.util.Map;
public class Tests {
private static interface ComparableMap< K,V>扩展Map< K,V>,Comparable {}
public static void main(String [] args){
func(getString());
private static void func(Comparable ... input){
System.out.println(Arrays.toString(input));
private static void func(ComparableMap<?,?> m){
System.out.println(m);
}
private static< T extends Comparable> T getString(){
return(T)aaa;
$ b 在java 7中它正常工作,在java 8 I中'm gets:
java.lang.ClassCastException:java.lang.String不能转换为tests.Tests $ ComparableMap
如果我将一个函数定义更改为:
私人静态< T> T getString(){
return(T)aaa;
}
编译将失败,并显示:error:
引用func不明确为什么Java 8编译器在第一种情况下不会失败? (看看bug)
是否有可能改变第二个重载函数,以便用varargs参数调用第一个函数而不改变调用本身?
解决方案 编译器错误
在第一种情况下,需要方法 getString
返回一个 Comparable
实例。编译器查找 func
方法的重载,并且它只找到一个可以接受 Comparable : func(Comparable ... input)
。 Map
不会实现该接口,所以第二个重载不适用。没有歧义。
在第二种情况下, getString
可以返回任何内容。两种超载都有效,所以存在一个模糊性。请注意,对T的演员阵容在这两种情况下都是不安全的/错误的。
美式投球
你编写的通用方法基本上告诉编译器我可以返回任何你想要实现 Comparable
>的类的实例。
可以说我有以下代码:
String str = getString();
Integer num = getString();
这段代码将被编译, String
和 Integer
实现 Comparable
界面。第二行在运行时会失败:代码尝试将 String 转换为 Integer
。
您的第二种情况也出于我上面解释的相同原因。它承诺它可以返回任何你想要的类型。它显然无法遵守这个承诺( Runnable
这是一个随机的例子,它可能是任何东西):
Runnable run = getString()
h2>
编译器会看到两个匹配的重载, func(Comparable ... input)
和 func(ComparableMap<?,?> m)
。它更喜欢第二个,因为可变参数方法总是最后被选中(为了兼容性的原因)。所有这些都是corect行为。
然后代码抛出ClassCastException,因为你的 getString
方法不会保留它承诺(让调用者决定返回什么样的 Comparable
)。
如何解决它?
最根本的问题是你的 getString
方法做出了错误的承诺。因此,我真的不知道该代码试图完成什么。如果你能详细说明我们可以帮助你更进一步。
I'm trying to migrate Java 7 code to Java 8, so I've code similar to:
package tests;
import java.util.Arrays;
import java.util.Map;
public class Tests {
private static interface ComparableMap<K,V> extends Map<K,V>, Comparable {}
public static void main(String[] args) {
func(getString());
}
private static void func(Comparable...input){
System.out.println(Arrays.toString(input));
}
private static void func(ComparableMap <?,?> m){
System.out.println(m);
}
private static <T extends Comparable> T getString(){
return (T) "aaa";
}
}
In java 7 it working properly, in java 8 I'm getting:
java.lang.ClassCastException: java.lang.String cannot be cast to tests.Tests$ComparableMap
And in case I'm changing one function definition to:
private static <T> T getString(){
return (T) "aaa";
}
compilation will fail with: error:
reference to func is ambiguous
Why Java 8 compiler not failing in first case? (Looks bug to me)
Is it possible to change 2nd overloaded function, in order to get called first function with varargs argument without changing call itself?
解决方案 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.
这篇关于Java 8通用函数应该是不明确的,但是在运行时会失败的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!
查看全文