有人可以帮助我理解这段代码背后的逻辑:
import java.util.List;
import java.util.Arrays;
interface DoubleValue<T> {
public void dv(T e);
}
public class InTest2 {
public static void main(String[] a) {
DoubleValue<Number> func = e -> System.out.println(e.doubleValue());
List<Number> l = Arrays.asList(1, 2, 3);
InTest2.sumOfListNotWorking(l, func);
InTest2.sumOfListWorking(l, func);
InTest2.sumOfListWorkingSuper(l, func);
}
// I thought this should work
public static void sumOfListNotWorking(List<? extends Number> list, DoubleValue<? extends Number> f) {
for (Number n : list)
f.dv(n); // This line give error: The method dv(capture#2-of ? extends Number) in the type DoubleValue<capture#2-of ? extends Number> is not applicable for the arguments (Number)
}
public static void sumOfListWorking(List<? extends Number> list, DoubleValue<Number> f) {
for (Number n : list)
f.dv(n);
}
public static void sumOfListWorkingSuper(List<? extends Number> list, DoubleValue<? super Number> f) {
for (Number n : list)
f.dv(n);
}
}
sumOfListNotWorking:
在这里,我传递给DoubleValue.dv(<? extends Number> e)
一个号码,我觉得它没问题。
但是编译器说它不是。为什么呢?
我希望将DoubleValue<Number>.dv
作为e -> e.doubleValue()
,这应该是典型的消费者:我得到价值<? extends Number>
并对其做点什么。
sumOfListWorkingSuper:
sumOfListWorkingSuper
的行为也困扰着我。
接口DoubleValue<? super Number>
不能成为消费者原因值<? super Number>
无法就地更改(数字是不可变的),但编译器可以使用它。
更新:
显然,我并没有正确理解&#34;制作人&#34;和&#34;消费者&#34;。
sumOfListNotWorking:
这个方法没有编译,因为我使用:
List<? extends Number> list
作为制作人(在我拿出的方法中)
带循环的列表中的值)。 DoubleValue<? extends Number>
作为消费者(在方法中我将Number
传递给f.dv(n)
),但当我尝试将值Number
传递给f
时,编译器告诉我f
被定义为生产者(<? extends Number>
- 有一些值为Number
或它的子女)并且它不能接受任何值。如果我转到f
参数DoubleValue<Integer>
然后我会尝试将Number
放在应该Integer
的位置怎么办 - 这是不可能的。发生所有这些错误是因为我定义了生产者而不是消费者。感谢您在消费者和制作人的逻辑中指出单词accept。
答案 0 :(得分:2)
List<? extends Number>
表示&#34;我们不知道此列表包含的内容,但无论它是什么,它都是数字或数字本身的后代。&#34;
同样地,DoubleValue<? extends Number>
表示&#34;我们不知道DoubleValue可以接受什么操作,但无论它接受什么,它都是数字或数字本身的后代&#34;
这里的相关部分是&#34;我们不知道它接受了什么&#34;。我们不知道,所以你不能给它任何东西,并期望它会被接受:因为你不知道它是否被接受。其余信息无关紧要。它在List<? extends Number>
中是相关的,因为至少我们知道它给出的任何元素,在它们被发出后可以安全地转换为数字。但是你的DoubleValue类并没有给出任何东西。它只涉及事物。所有这些&#34;但我们知道它是&#34;的后代。完全没用。
<? extends Stuff>
对于提供对象的类很有用。对那些没有发出物品的人来说,它毫无用处。
<? super Stuff>
对于接收对象的类很有用。对那些不接受物品的人来说,它毫无用处。
答案 1 :(得分:1)
除@ kumesana的答案外,您还可以通过以下方式解决问题:
public static <T extends Number> void sumOfListNotWorking(
List<? extends T> list,
DoubleValue<? super T> f) {
for (T n : list)
f.dv(n);
}
你只需要做那个&#34;未知&#34;输入已知的通配符(T
)。
另请参阅PECS规则。在这里,list
提供项目(即它是生产者),f
接受项目(它是消费者)。因此输入list
应该扩展T
,输入f
应该超级T
。这允许传递List<Integer>
和DoubleValue<Number>
。