猿问

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

我有这个类称为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());

    }

}



慕虎7371278
浏览 112回答 2
2回答

繁星淼淼

根据JLS §15.12.2.2:参数表达式被认为与潜在适用方法的适用性相关,m除非它具有以下形式之一:一个隐式类型的 lambda 表达式1。一个不精确的方法引用表达式2。[...]所以:verify("bar",&nbsp;tokens.get("foo",&nbsp;e&nbsp;->&nbsp;String.valueOf(e)));在重载解析期间,隐式类型的 lambda 表达式e -> String.valueOf(e)从适用性检查中跳过 - 两种verify(...)方法都适用 - 因此存在歧义。相比之下,这里有一些可行的示例,因为类型是明确指定的:verify("bar",&nbsp;tokens.get("foo",&nbsp;(Function<Object,&nbsp;String>)&nbsp;e&nbsp;->&nbsp;String.valueOf(e))); verify("bar",&nbsp;tokens.get("foo",&nbsp;(Function<Object,&nbsp;String>)&nbsp;String::valueOf));1 - 隐式类型的 lambda 表达式是一个 lambda 表达式,其中推断出其所有形式参数的类型。2 - 一个不精确的方法引用 - 一个有多个重载的方法。

qq_笑_17

有String.valueOf(...)不同参数的多种实现。编译器不知道你要调用哪一个。编译器无法看到所有可能的方法实际上都返回 a&nbsp;String,因此调用哪个方法并不重要。由于编译器不知道返回类型是什么,因此它无法推断出Function<...,...>表达式的类型,因此它无法理解您手头是否会有 aFunction或其他东西,因此无法判断您是否想调用该get方法一个Function或一个Class。如果您不String::valueOf使用 usee -> String.valueOf(e)那么编译器可以推断出更多,但它仍然不会理解您将始终返回 aString并因此将其解释为Function<Object, Object>您的verify方法有问题。e -> e.toString我不完全理解,我不明白为什么编译器不能在String这里推断为返回类型。它推断Object并执行与前一个案例完全相同的事情。如果您将操作拆分为String&nbsp;s&nbsp;=&nbsp;tokens.get("baz",&nbsp;e&nbsp;->&nbsp;e.toString()); verify("bat",&nbsp;s);&nbsp;&nbsp;//&nbsp;line&nbsp;21那么它就可以工作了,因为编译器可以R从s.&nbsp;通过显式指定,它的工作方式相同R:verify("bat",&nbsp;tokens.<String>get("baz",&nbsp;e&nbsp;->&nbsp;e.toString()));&nbsp;&nbsp;//&nbsp;line&nbsp;21String.class编译器很容易理解您要调用该get(Class)方法。Object::toString因为编译器知道这将是一个Function<Object, String>.
随时随地看视频慕课网APP

相关分类

Java
我要回答