[英]Java compiler prohibit the creation in the inner class method with same name as in the outer class if the signatures are different
[英]Java compiler: How can two methods with the same name and different signatures match a method call?
我有這個名為Container
類:
public class Container {
private final Map<String, Object> map = new HashMap<>();
public void put(String name, Object value) {
map.put(name, value);
}
public Container with(String name, Object value) {
put(name, value);
return this;
}
public Object get(String name) {
return map.get(name);
}
public <R> R get(String name, Function<Object, R> mapper) {
Object value = get(name);
if (null == value) {
return null;
}
return mapper
.apply(value);
}
public <R> R get(String name, Class<R> type) {
Object value = get(name);
if (null == value) {
return null;
}
if (type.isAssignableFrom(value.getClass())) {
return type
.cast(value);
}
throw new ClassCastException(String
.format("%s -> %s", value.getClass(), type));
}
}
和名為Token
的類:
public class Token {
private String value;
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
public Token withValue(String value) {
setValue(value);
return this;
}
}
最后是Token
類的測試類
public class TokenTest {
@Test
public void verifyToken() {
verify("bar", new Token()
.withValue("bar"));
}
@Test
public void verifyContainer() {
Container tokens = new Container()
.with("foo", "bar")
.with("baz", "bat");
verify("bar", tokens.get("foo", String.class));
verify("bat", tokens.get("baz", String::valueOf)); // line 21
}
private void verify(String expected, String actual) {
verify(expected, new Token()
.withValue(actual));
}
private void verify(String expected, Token actual) {
Assert
.assertEquals(expected, actual.getValue());
}
}
測試在eclipse中編譯並運行文件。
當建立在commad線上時
mvn clean test
引發編譯錯誤:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.8.0:testCompile (default-testCompile) on project ambiguous: Compilation failure
[ERROR] /C:/data/projects/java/ambiguous/src/test/java/ambiguous/TokenTest.java:[21,9] reference to verify is ambiguous
[ERROR] both method verify(java.lang.String,java.lang.String) in ambiguous.TokenTest and method verify(java.lang.String,ambiguous.Token) in ambiguous.TokenTest match
當我將第21
行更改為其中之一時,編譯也會失敗
verify("bat", tokens.get("baz", e -> String.valueOf(e)));
verify("bat", tokens.get("baz", e -> e.toString));
當我將行更改為其中一行時
verify("bat", tokens.get("baz", String.class));
verify("bat", tokens.get("baz", Object::toString));
編譯成功。
我無法理解為什么會出現這種編譯錯誤。
我遇到了以下鏈接裝箱和拆箱 , 多種通用類型和交叉點類型以及這個eclipse編譯器錯誤,但我仍然無法提及上述原因。
我的問題是,當映射器String::valueOf
傳遞給get
方法時,是什么讓編譯器認為verify
方法的兩個簽名都匹配?
對於編譯,使用以下jdk(使用maven和gradle):
$ java -version
openjdk version "1.8.0_201-1-ojdkbuild"
OpenJDK Runtime Environment (build 1.8.0_201-1-ojdkbuild-b09)
OpenJDK 64-Bit Server VM (build 25.201-b09, mixed mode)
根據JLS§15.12.2.2 :
除非具有以下形式之一,否則參數表達式被認為與可能適用的方法
m
適用性相關 :
- 隱式類型的lambda表達式1 。
- 一個不精確的方法引用表達式2 。
- [...]
因此:
verify("bar", tokens.get("foo", e -> String.valueOf(e)));
隱式類型化的lambda表達式e -> String.valueOf(e)
在重載解析期間從適用性檢查中跳過 - 兩種verify(...)
方法都適用 - 因此存在歧義。
相比之下,以下是一些可行的示例,因為明確指定了類型:
verify("bar", tokens.get("foo", (Function<Object, String>) e -> String.valueOf(e)));
verify("bar", tokens.get("foo", (Function<Object, String>) String::valueOf));
1 - 隱式類型的lambda表達式是lambda表達式,其中推斷出所有形式參數的類型。
2 - 一個不精確的方法引用 - 一個具有多個重載的引用。
String.valueOf(...)
有多個具有不同參數的實現。 編譯器不知道您要調用哪一個。 編譯器無法看到所有可能的方法實際返回一個String
,因此調用哪個方法並不重要。 由於編譯器不知道返回類型是什么,因此它無法推斷出正確的Function<...,...>
作為表達式的類型,因此無法理解你是否有一個Function
或其他東西在手邊,因此無法判斷是否要使用Function
或Class
調用get
方法。
如果您使用e -> String.valueOf(e)
代替String::valueOf
那么編譯器可以推斷出更多但是它仍然不會理解您將始終返回一個String
並因此將其解釋為Function<Object, Object>
然后你的verify
方法有問題。
e -> e.toString
我不完全理解,我不明白為什么編譯器無法在這里推斷String
作為返回類型。 它推斷出Object
並完成與前一種情況完全相同的事情。 如果將操作拆分為
String s = tokens.get("baz", e -> e.toString());
verify("bat", s); // line 21
然后它起作用,因為編譯器可以從s
的類型推斷出泛型R
它通過顯式指定R
方式相同:
verify("bat", tokens.<String>get("baz", e -> e.toString())); // line 21
String.class
編譯器很容易理解你想要調用get(Class)
方法。
Object::toString
有意義,因為編譯器知道這將是一個Function<Object, String>
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.