如果我有一個泛型<T2 extends T1>,編譯器會推斷T1 super T2嗎?
我有一個更復雜的集合,我將其簡化為下面的 MWE。該集合應可與具有任何子型別元素的任何此類集合合并。
現在我想知道,為什么不接受對forEachin的呼叫。merge它失敗了
java.util.function.Consumer<java.util.Optional> 無法轉換為 java.util.function.Consumer<java.util.Optional<? 超級T2>>
我已經在下圖中描述了型別關系。在merge,T2延伸T1。forEach對物件的呼叫other,因此T1ofthis成為?ofother.forEach并且T2ofthis.merge是T1of other。因此,this'T1應該被接受為other' 的上級T1。
我也嘗試public void merge(Group<? extends T> other)過同樣的結果。并且public void merge(Group<T> other)不接受帶有任何子型別元素的此類集合T1。
MWE:
class Group<T1> {
public <T2 extends T1> void merge(Group<T2> other) {
Consumer<Optional<T1>> task = t -> t.ifPresentOrElse(this::foo, this::bar);
other.forEach(task);
}
public Collection<Optional<T1>> values() {
return List.of();
}
public void forEach(Consumer<Optional<? super T1>> consumer) {
values().forEach(consumer);
}
private void foo(T1 t) {}
private void bar() {}
}
關系:
this.T1 -becomes-> other.forEach.?
^ |
| super
extends |
| v
this.merge.T2 -is-> other.T1
uj5u.com熱心網友回復:
如果你有 aConsumer<Optional<? super T1>> consumer那么你可以將它(給accept(T)方法)傳遞給 anOptional<Object>因為Object是T1.
另一方面,您不能傳遞Optional<Object>toConsumer<Optional<T1>> task因為T1可能不是Object。
因此,您不能將 分配Consumer<Optional<T1>> task給Consumer<Optional<? super T1>> consumer以防止您的消費者被傳遞它不期望的型別的物件。
uj5u.com熱心網友回復:
您可以使用解決您的問題
class Group<T1> {
public <T2 extends T1> void merge(Group<T2> other) {
Consumer<Optional<? extends T1>> task=t->t.ifPresentOrElse(this::foo, this::bar);
other.forEach(task);
}
public Collection<Optional<T1>> values() {
return List.of();
}
public void forEach(Consumer<? super Optional<T1>> consumer) {
values().forEach(consumer);
}
private void foo(T1 t) {}
private void bar() {}
}
這是PECS規則的應用。
您task將 視為Optional生產者,因此,必須宣告Optional<? extends T1>允許可選項生成 的子型別T1。我們知道 optional 將始終充當生產者,但 Java 的泛型型別系統沒有類始終充當生產者或消費者的概念,因此? extends T1此處需要顯式。
forEach接收一個消費者,即使在介面名稱中也是如此,因此宣告? super …該消費者可能是Optional<T1>. 這不僅包括Object的超類Optional,而且還包括Optional<? extends T1>when T1 := T2,如在內部的呼叫中merge,asOptional<? extends T1>是 的超型別Optional<T2>。
當然,您也可以通過簡單地使用來解決問題
Consumer<Optional<T2>> task = t -> t.ifPresentOrElse(this::foo, this::bar);
因為這只需要foo接受一個T2引數,它總是這樣做,T2就像T1. 但是更改簽名forEach以提高靈活性始終是一個好舉措。由于它是一種public方法,因此可能會有其他呼叫者從中受益。
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/426690.html
上一篇:不同的回傳值取決于通用常量的值
