ジェネリッククラスのJava 8のあいまいなメソッドリファレンス

xendoo:

以下のコードは、Java 7ではコンパイルおよび実行できますが、Java 1.8.0 u25ではコンパイルできません。

public class GenericTest {

    public static class GenericClass<T> {
        T value;

        public GenericClass(T value) {
            this.value = value;
        }
    }

    public static class SecondGenericClass<T> {
        T value;

        public SecondGenericClass(T value) {
            this.value = value;
        }
    }


    public static<T >void verifyThat(SecondGenericClass<T> actual, GenericClass<T> matcher) {
    }

    public static<T >void verifyThat(T actual, GenericClass<T> matcher) {
    }

    @Test
    public void testName() throws Exception {
        verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""));
    }

}

Java 8のエラーメッセージは次のようになります。

Error:(33, 9) java: reference to verifyThat is ambiguous
  both method <T>verifyThat(com.sabre.ssse.core.dsl.GenericTest.SecondGenericClass<T>,com.sabre.ssse.core.dsl.GenericTest.GenericClass<T>) in com.sabre.ssse.core.dsl.GenericTest and method <T>verifyThat(T,com.sabre.ssse.core.dsl.GenericTest.GenericClass<T>) in com.sabre.ssse.core.dsl.GenericTest match


https://docs.oracle.com/javase/specs/jls/se8/html/jls-15.html#jls-15.12.2 https://docs.oracle.com/の間のすべての変更を確認しました
javase / specs / jls / se7 / html / jls-15.html#jls-15.12.2

しかし、私はこの振る舞いの正確な理由に気付かなかった。

編集:

いくつかのコメントに答えるだけで、Java 7と8の両方のコンパイラーがそのような呼び出しを処理できることは非常に明らかです(シグニチャーは、コンパイル時の型消去後に残されるものと同様です)。

public static void verifyThat(SecondGenericClass actual, GenericClass matcher) {
}

public static void verifyThat(Object actual, GenericClass matcher) {
}

@Test
public void testName() throws Exception {
    verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""));
}

両方のジェネリックメソッドに対して生成され、消去されるバイトコードは同じで、次のようになります。

public static verifyThat(Lcom/sabre/ssse/core/dsl/GenericTest$SecondGenericClass;Lcom/sabre/ssse/core/dsl/GenericTest$GenericClass;)V
public static verifyThat(Ljava/lang/Object;Lcom/sabre/ssse/core/dsl/GenericTest$GenericClass;)V

Edit2:

javac 1.8.0_40でのコンパイルが同じエラーで失敗する

ホルガー:

JLS、§15.12.2.5章最も具体的な方法の選択は読みにくいですが、興味深い要約が含まれています。

非公式な直感は、最初のメソッドによって処理された呼び出しをコンパイル時の型エラーなしで他のメソッドに渡すことができる場合、1つのメソッドが別のメソッドよりも具体的であるということです。

次の例を使用して、これを簡単に否定できます。

GenericTest.<String>verifyThat( // invokes the first method
    new SecondGenericClass<>(""), new GenericClass<>(""));
GenericTest.<SecondGenericClass<String>>verifyThat( // invokes the second
    new SecondGenericClass<>(""), new GenericClass<>(null));

したがって、ここには最も具体的なメソッドはありませんが、例が示すように、引数を使用してどちらのメソッドも呼び出すことが可能で、他のメソッドを適用できなくなります。

Java 7では、(コンパイラの)型引数を見つけてより多くのメソッドを適用できるようにする(限られた型の推論)ため、限られた方法でメソッドを適用不可能にする方が簡単でした。式の引数から推測されnew SecondGenericClass<>("")た型があり、それだけです。したがって、呼び出しの場合、引数には型があり、そのためメソッドが適用できなくなりました。SecondGenericClass<String>""verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""))SecondGenericClass<String>GenericClass<String><T> void verifyThat(T,GenericClass<T>)

Java 7(さらにはJava 6)のあいまいさを示すあいまいな呼び出しの例があることに注意してくださいverifyThat(null, null);を使用すると、コンパイラエラーが発生しjavacます。

しかし、Java 8には呼び出しの適用性の推論(JLS 7とはまったく新しい章があります)があり、コンパイラーはメソッドの候補を適用できる型引数を選択できます(ネストされた呼び出しを通じて機能します)。あなたはあなたの特別な場合のためにそのような型引数を見つけることができます、あなたは両方に合う型引数を見つけることさえできます、

GenericTest.<Object>verifyThat(new SecondGenericClass<>(""), new GenericClass<>(""));

(Java 8では)あいまいさはあいまいですが、Eclipseでも同意しています。対照的に、呼び出し

verifyThat(new SecondGenericClass<>(""), new GenericClass<String>(""));

は、2番目のメソッドを適用不可能にして最初のメソッドを呼び出すのに十分なほど具体的であり、と同様にのタイプnew GenericClass<>("")が固定されているJava 7で何が起こっているかについてのヒントを与えます。GenericClass<String>new GenericClass<String>("")


つまり、Java 7からJava 8に(大幅に)変更された最も具体的なメソッドを選択するのではなく、型推論が改善されたことによる適用性です。どちらの方法も適用できるようになると、どちらの方法も他よりも具体的でないため、呼び出しはあいまいになります。

この記事はインターネットから収集されたものであり、転載の際にはソースを示してください。

侵害の場合は、連絡してください[email protected]

編集
0

コメントを追加

0

関連記事

ジェネリック型のJava 8メソッドリファレンス

javaオプションのインターフェースメソッド:あいまいなメソッドリファレンス

クラス型のないジェネリックメソッド?

ジェネリッククラスのJavaジェネリックメソッド

Java:生の匿名クラスはそのメソッドでジェネリック型を失います

Javaのジェネリッククラス内のdoubleメソッド

Dartの非ジェネリッククラスのジェネリックフィールド/メソッド

Javaのジェネリッククラスの非ジェネリックコンストラクタ

ジェネリッククラスの静的メソッド?

ジェネリッククラス型制約のあるジェネリックメソッド

非ジェネリッククラスのジェネリッククラスメソッド

Javaのジェネリッククラスのジェネリック型メンバーを比較する方法

ジェネリックスを使用したJavaのファクトリメソッドパターン、方法

MatlabでのJavaジェネリッククラスの使用

内部クラスのJavaのジェネリック型

java クラス内の複数のジェネリック型

クラス java の複数のジェネリック型

Pythonのジェネリッククラスファクトリ

Javaジェネリック:ジェネリックインターフェイスでジェネリッククラスのIDを取得する方法は?

Javaジェネリックの互換性のないクラス

Javaのジェネリックスとメソッド

ファンクショナルインターフェイスパラメータータイプのメソッドのJavaジェネリック

Javaのジェネリッククラスのスーパークラス

クラス<T>のJavaジェネリック

Javaジェネリッククラス-タイプの決定

Javaのジェネリック型付き内部クラス

Javaのジェネリッククラス引数

Javaのジェネリッククラス

このクラスが非ジェネリックな方法で使用されている場合、Javaジェネリッククラスはすべてのフィールドのジェネリック情報を見逃しますか?

TOP 一覧

  1. 1

    グラフからテーブルに条件付き書式を適用するにはどうすればよいですか?

  2. 2

    ソートされた検索、ターゲット値未満の数をカウント

  3. 3

    Unity:未知のスクリプトをGameObject(カスタムエディター)に動的にアタッチする方法

  4. 4

    セレンのモデルダイアログからテキストを抽出するにはどうすればよいですか?

  5. 5

    Ansibleで複数行のシェルスクリプトを実行する方法

  6. 6

    Reactでclsxを使用する方法

  7. 7

    tkinterウィンドウを閉じてもPythonプログラムが終了しない

  8. 8

    Windows 10 Pro 1709を1803、1809、または1903に更新しますか?

  9. 9

    Pythonを使用して同じ列の同じ値の間の時差を取得する方法

  10. 10

    PowerShellの分割ファイルへのヘッダーの追加

  11. 11

    Chromeウェブアプリのウェブビューの高さの問題

  12. 12

    BLOBストレージからデータを読み取り、Azure関数アプリを使用してデータにアクセスする方法

  13. 13

    Crashlytics:コンパイラー生成とはどういう意味ですか?

  14. 14

    GoDaddyでのCKEditorとKCfinderの画像プレビュー

  15. 15

    Windows 10の起動時間:以前は20秒でしたが、現在は6〜8倍になっています

  16. 16

    MLでのデータ前処理の背後にある直感

  17. 17

    モーダルダイアログを自動的に閉じる-サーバーコードが完了したら、Googleスプレッドシートのダイアログを閉じます

  18. 18

    reCAPTCHA-エラーコード:ユーザーの応答を検証するときの「missing-input-response」、「missing-input-secret」(POSTの詳細がない)

  19. 19

    STSでループプロセス「クラスパス通知の送信」のループを停止する方法

  20. 20

    ファイル内の2つのマーカー間のテキストを、別のファイルのテキストのセクションに置き換えるにはどうすればよいですか?

  21. 21

    ネットワークグラフで、ネットワークコンポーネントにカーソルを合わせたときに、それらを強調表示するにはどうすればよいですか?

ホットタグ

アーカイブ