Javaコンパイラ:どのように同じ名前と異なるシグネチャを持つ2つのメソッドは、メソッドの呼び出しを一致させることができますか?

A4L:

私はと呼ばれるこのクラスを持っています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());
    }
}

日食のテストコンパイルと実行が単にファイル。

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));

コンパイルが成功しています。

このcompiliationエラーが発生する理由は分かりましたができません。

私はfollwongリンクに出くわしたボクシングとアンボクシング複数のジェネリック型と交差点の種類と、この日食のコンパイラのバグが、私はまだ上記の原因に関係することはできません。

私の質問は、コンパイラが両方の署名と思いせるものであり、verifyマッパーをするときの方法が一致しているString::valueOfに渡されるget方法?

コンパイルのために以下の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)
オレクサンドルPyrohov:

よると、JLS§15.12.2.2

引数の式が考慮される適用に関連する潜在的に適用可能な方法のためにm、それは、次のいずれかの形式を持っていない限り:

  • 暗黙に型付けされたラムダ式1
  • 不正確なメソッド参照式2
  • [...]

したがって:

verify("bar", tokens.get("foo", e -> String.valueOf(e)));

暗黙に型付けされたラムダ式は、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 -アン暗黙に型付けされたラムダ式は、そのすべての仮パラメータの型が推測されるラムダ式、です。
2 -不正確なメソッドリファレンス-複数のオーバーロードを有するもの。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=234053&siteId=1