为了账号安全,请及时绑定邮箱和手机立即绑定

Java编译器:两个同名不同签名的方法如何匹配一个方法调用?

Java编译器:两个同名不同签名的方法如何匹配一个方法调用?

慕虎7371278 2022-12-15 14:54:30
我有这个类称为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());    }}
查看完整描述

2 回答

?
繁星淼淼

TA贡献1775条经验 获得超11个赞

根据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 - 一个不精确的方法引用 - 一个有多个重载的方法。


查看完整回答
反对 回复 2022-12-15
?
qq_笑_17

TA贡献1818条经验 获得超7个赞

String.valueOf(...)不同参数的多种实现。编译器不知道你要调用哪一个。编译器无法看到所有可能的方法实际上都返回 a String,因此调用哪个方法并不重要。由于编译器不知道返回类型是什么,因此它无法推断出Function<...,...>表达式的类型,因此它无法理解您手头是否会有 aFunction或其他东西,因此无法判断您是否想调用该get方法一个Function或一个Class


如果您不String::valueOf使用 usee -> String.valueOf(e)那么编译器可以推断出更多,但它仍然不会理解您将始终返回 aString并因此将其解释为Function<Object, Object>您的verify方法有问题。


e -> e.toString我不完全理解,我不明白为什么编译器不能在String这里推断为返回类型。它推断Object并执行与前一个案例完全相同的事情。如果您将操作拆分为

String s = tokens.get("baz", e -> e.toString());
verify("bat", s);  // line 21

那么它就可以工作了,因为编译器可以Rs. 通过显式指定,它的工作方式相同R

verify("bat", tokens.<String>get("baz", e -> e.toString()));  // line 21

String.class编译器很容易理解您要调用该get(Class)方法。


Object::toString因为编译器知道这将是一个Function<Object, String>.


查看完整回答
反对 回复 2022-12-15
  • 2 回答
  • 0 关注
  • 111 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信