我很努力地理解Java中的差異是如何工作的。Java類型差異,泛型類型的消費者
在以下示例中,我定義了一個函數test
,它需要Consumer
。該函數被定義爲沒有反轉,因此我預計Consumer<Object>
不是Consumer<Pair<Animal, Animal>>
的子類型。然而,代碼編譯和測試接受lambda 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的評論,參考superAction
被脫到Consumer<Pair<Animal, Animal>>
不是一個Consumer<Object>
。
正確的類型給予test
方法是一樣的東西:
void test(Consumer<? super Pair<? extends Animal, ? extends Animal>>)
這種類型將使我們能夠通過一個Consumer<Object>
到test
,也使我們能夠調用帶參數的消費者喜歡Pair<Dog, Dog>
,而不是隻Pair<Animal, Animal>
。
作爲後續問題,使用此更新的測試類型,它不再接受像void exactMatchAction<Pair<Animal, Animal>>
這樣的方法參考,只有void exactMatchAction<Pair<? extends Animal, ? extends Animal>>
。爲什麼是這樣?
據我所知,沒有警告。 – asp
不知道這是如何實現的,但它確實有道理。對象的消費者也可以消費對。如果你改變這個參數來表示一個字符串,你會得到一個錯誤,對嗎? – Thilo
真的,我不知道。但我的猜測是這與'@ FunctionalInterface'的處理方式有關。它可能不關心接口本身的類型參數,只是它們在方法中被引用的方式。所以'Object - > void'方法可以用作'Pair <> - > void',因爲如果它可以消耗*任何對象*,那麼當然可以消耗一對。 – ryachza