Java 8:对 [method] 的引用不明确
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32294140/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java 8: Reference to [method] is ambiguous
提问by Ken
Does anybody understand why the following code will compile fine in Java 7 and below, but fails with Java 8.
有没有人理解为什么以下代码可以在 Java 7 及更低版本中正常编译,但在 Java 8 中失败。
public static void main(String[] args) throws Exception {
put(get("hello"));
}
public static <R> R get(String d) {
return (R)d;
}
public static void put(Object o) {
System.err.println("Object " + o);
}
public static void put(CharSequence c) {
System.err.println("CharSequence " + c);
}
public static void put(char[] c) {
System.err.println("char[] " + c);
}
The get method has a generic return type. In JDK 7 and below this compiles fine and the put method with the Object parameter is chosen. In JDK 8 this cannot be compiled, indicating the put method is ambiguous.
get 方法有一个通用的返回类型。在 JDK 7 及以下版本中,此编译良好,并选择了带有 Object 参数的 put 方法。在 JDK 8 中无法编译,说明 put 方法不明确。
Apparently JDK 8 is skipping over the Object-parameter method and finding the last two sub-Object-parameter methods and complaining about them (i.e. if you add another put method with some other parameter type, the compiler will switch and complain about the new last two methods)
显然 JDK 8 正在跳过 Object-parameter 方法并找到最后两个子 Object-parameter 方法并抱怨它们(即,如果您添加另一个具有其他参数类型的 put 方法,编译器将切换并抱怨新的最后一个两种方法)
This seems like a bug.
这似乎是一个错误。
回答by Codebender
Your problem is a side-effect of Generalized Target-type Inference, an improvement in Java 8.
您的问题是Generalized Target-type Inference的副作用,这是 Java 8 的改进。
What is Target-type Inference
什么是目标类型推理
Let's take your example method,
让我们以您的示例方法为例,
public static <R> R get(String d) {
return (R)d;
}
Now, in the method above, the generic parameter R
cannot be resolved by the compiler because there's no parameter with R
.
现在,在上面的方法中,R
编译器无法解析泛型参数,因为没有带R
.
So, they introduced a concept called Target-type Inference
, which allows the parameter to be inferredbased on the assignment parameter.
因此,他们引入了一个名为 的概念Target-type Inference
,它允许根据赋值参数来推断参数。
So, if you do,
所以,如果你这样做,
String str = get("something"); // R is inferred as String here
Number num = get("something"); // R is inferred as Number here
This works well in Java 7. But the following does not,
这在 Java 7 中运行良好。但以下不,
put(get("something");
static void Put(String str) {} //put method
Because type inference worked only for direct assignments.
因为类型推断仅适用于直接赋值。
If there's no direct assignment, then the generic type was inferred as Object
.
如果没有直接赋值,则泛型类型被推断为Object
.
So, when you compiled the code with Java 7, your put(Object)
method was called without any problems.
因此,当您使用 Java 7 编译代码时,您的put(Object)
方法被毫无问题地调用。
What they did in Java 8
他们在 Java 8 中做了什么
They improved the type inferenceto infer the type from method callsand chained method calls
他们改进了类型推断以从方法调用和链式方法调用中推断类型
More details about them hereand here
So now, you can directly call put(get("something"))
and the generic type will be inferredbased on the parameter of the put()
method.
所以现在可以直接调用put(get("something"))
,根据方法的参数推断泛型类型。put()
But as you know, the methods, put(Charsequence)
and put(char[])
match the arguments. So there's the ambiguity.
但如您所知,方法put(Charsequence)
和put(char[])
参数匹配。所以有歧义。
Fix?
使固定?
Just tell the compiler exactly what you want,
只要告诉编译器你想要什么,
put(TestClass.<CharSequence>get("hello")); // This will call the put(CharSequence) method.
回答by Amila
Looks like this is a known incompatibility.
看起来这是一个已知的不兼容。
See "Area: Tools / javac" section of this article.And this bug.
请参阅本文的“区域:工具/javac”部分。还有这个bug。
Synopsis
The following code which compiled, with warnings, in JDK 7 will not compile in JDK 8:
概要
以下在 JDK 7 中编译并带有警告的代码不会在 JDK 8 中编译:
import java.util.List;
class SampleClass {
static class Baz<T> {
public static List<Baz<Object>> sampleMethod(Baz<Object> param) {
return null;
}
}
private static void bar(Baz arg) {
Baz element = Baz.sampleMethod(arg).get(0);
}
}
Compiling this code in JDK 8 produces the following error:
在 JDK 8 中编译此代码会产生以下错误:
SampleClass.java:12: error:incompatible types: Object cannot be converted to Baz
Baz element = Baz.sampleMethod(arg).get(0);
Note: SampleClass.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
1 error
In this example, a raw type is being passed to the sampleMethod(Baz) method which is applicable by subtyping (see the JLS, Java SE 7 Edition, section 15.12.2.2).
An unchecked conversion is necessary for the method to be applicable, so its return type is erased (see the JLS, Java SE 7 Edition, section 15.12.2.6). In this case the return type of sampleMethod(Baz) is java.util.List instead of java.util.List> and thus the return type of get(int) is Object, which is not assignment-compatible with Baz.
在此示例中,原始类型被传递给可通过子类型化应用的 sampleMethod(Baz) 方法(请参阅 JLS,Java SE 7 版,第 15.12.2.2 节)。
要使该方法适用,必须进行未经检查的转换,因此它的返回类型将被删除(请参阅 JLS,Java SE 7 版,第 15.12.2.6 节)。在这种情况下,sampleMethod(Baz) 的返回类型是 java.util.List 而不是 java.util.List>,因此 get(int) 的返回类型是 Object,它与 Baz 的赋值不兼容。