2015-09-06 12 views
6

Javaでの分散の仕組みを理解するのは苦労しています。ジェネリックタイプのJavaタイプ分散、

次の例では、testという関数を定義します。これはConsumerです。この関数は反反変数なしで定義されているので、Consumer<Object>Consumer<Pair<Animal, Animal>>のサブタイプではないと考えられます。しかし、コードはコンパイルされ、テストではラムダVariance:::superActionが受け入れられます。

私には何が欠けていますか?

import org.apache.commons.lang3.tuple.ImmutablePair; 
import org.apache.commons.lang3.tuple.Pair; 

import java.util.function.Consumer; 

public class Variance { 

    public static void main(String[] args) { 
    test(Variance::exactMatchAction); 
    test(Variance::superAction); 
    } 

    private static void exactMatchAction(Pair<Animal, Animal> pair) { 
    System.out.println(pair.getLeft().getClass().getName()); 
    } 

    private static void superAction(Object obj) { 
    System.out.println(obj.getClass().getName()); 
    } 

    private static void test(Consumer<Pair<Animal, Animal>> action) { 
    action.accept(ImmutablePair.of(new Animal(), new Animal())); 
    action.accept(ImmutablePair.of(new Dog(), new Dog())); 
    } 

    static class Animal { } 

    static class Dog extends Animal { } 
} 

編集は:Thieloさんのコメント@ごとに、参照superActionConsumer<Pair<Animal, Animal>>ませConsumer<Object>に脱糖されます。

test方法を与えるために、正しいタイプのようなものです:このタイプは、私たちがConsumer<Object>testにを渡すことができ、また、私たちはちょうどPair<Dog, Dog>の代わりのような引数を持つ消費者を呼び出すことができるようになります

void test(Consumer<? super Pair<? extends Animal, ? extends Animal>>) 

Pair<Animal, Animal>

このアップデートされたテスト用のタイプでは、void exactMatchAction<Pair<Animal, Animal>>のようなメソッド参照はもう受け付けません。void exactMatchAction<Pair<? extends Animal, ? extends Animal>>です。どうしてこれなの?

+0

私が知る限り、警告は表示されません。 – asp

+0

これがどのように実装されているかわかりませんが、意味があります。オブジェクトのコンシューマはペアを使用することもできます。そのパラメータを変更するとエラーが発生します。文字列、そうですか? – Thilo

+0

本当に、私は分かりません。しかし、私の推測では、これは '@ FunctionalInterface'の処理方法と関係があります。おそらく、インタフェース自体の型パラメータについては気にしませんが、メソッド内でどのように参照されているかのみです。だから、 'Object - > void'メソッドはおそらく' Pair <> - > void'として使うことができます。 – ryachza

答えて

0

Variance::superActionなどのメソッド参照式は、ポリ式(JLS8,15.13)です。ポリ表現のタイプは、式ターゲットタイプ(JLS8,15.3)(そのコンテキストで予想されるタイプ(JLS8,5)、つまりConsumer<Pair<Animal, Animal>>)の影響を受ける場合があります。

詳細は、JLS8,15.13.2に記載されています。基本的な考え方は、Consumerのような機能的なインターフェイスの種類の特別な処理があるということです。具体的には、メソッドタイプは、関数タイプ(Pair<Animal, Animal> -> void - Consumerはここでの型の考慮から消滅していることに注意してください)に対して一致するである必要があります。これは "identif [ying]"に対応する単一のコンパイル時宣言(と戻り値の型としてvoidを持っています)。ここで、宣言を「識別する」という概念は15.12.2に戻り、基本的にメソッドのオーバーロード解決プロセスを説明します。言い換えれば、言語はConsumer<Pair<Animal, Animal>>.accept()(すなわちPair<Animal, Animal>)で期待される関数パラメータをとり、これでメソッド参照を呼び出すことができるかどうかをチェックします(同じ名前の静的メソッドが複数ある場合にオーバーロードを解決します)。

関連する問題