java - 何时使用生产者和消费者逻辑/通配符 JAVA
问题描述
有人可以帮助我理解这段代码背后的逻辑:
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>
不能就地更改值(数字是不可变的),但编译器可以接受。
更新:
显然我没有正确理解“生产者”和“消费者”的逻辑。
sumOfListNotWorking:
此方法无法编译,因为我使用:
List<? extends Number> list
作为生产者(在方法中,我使用循环从列表中取出值)。DoubleValue<? extends Number>
作为消费者(在我传递Number
给的方法中f.dv(n)
),但是当我尝试将值传递Number
给f
编译器时告诉我,它f
被定义为生产者(<? extends Number>
- 有一些值Number
或者它的子级)并且它不能接受任何值。如果我传递给f
参数怎么办,DoubleValue<Integer>
那么我会尝试把Number
应该放在哪里Integer
- 这是不可能的。发生所有这些错误是因为我定义了生产者而不是消费者。
感谢您在消费者和生产者的逻辑中指出“接受”一词。
解决方案
List<? extends Number>
意思是“我们不知道这个 List 包含什么,但不管它是什么,它都是 Number 或 Number 本身的后代。”
同样,DoubleValue<? extends Number>
意味着“我们不知道这个 DoubleValue 可以接受什么来操作,但无论它接受什么,它都是 Number 或 Number 本身的后代”。
这里的相关部分是“我们不知道它接受什么”。我们不知道,所以你不能给它任何东西并期望它会被接受:因为你不知道它是否被接受。其余信息无关紧要。它在 a 中是相关的,List<? extends Number>
因为至少我们知道它给出的任何元素都可以在给出之后安全地转换为 Number 。但是你的 DoubleValue 类并没有给出任何东西。它只接受东西。所以所有那些“但我们知道它是它的后代”是完全没用的。
<? extends Stuff>
在给出对象的类上很有用。对于那些不给出对象的人来说,它是没有用的。
<? super Stuff>
在接受对象的类上很有用。对于那些不接受对象的人来说,它是无用的。
推荐阅读
- c# - 为什么当我的鼠标统一悬停在一个对象上时,它称它为错误的对象?
- javascript - 我将如何保持用户令牌状态,以便即使刷新我的按钮也会保留在页面上?
- javascript - 获取'/'之前的最后一个值
- sequelize.js - 使用“include.where”获取关联模型时包含关联模型中的所有实例
- ecdsa - 无法验证由 sol-wallet-adapter 签名的消息
- react-native - 当我们可以使用静态变量时,为什么还要使用 Context API?
- scikit-learn - 如何计算具有 70000 行、6 列的巨大矩阵中的点的距离?
- excel - 触发 Cells.Select 属性时停止工作表跳转到页面顶部
- python - 如何使用正则表达式删除一个单词和后面的所有内容
- reactjs - 单击屏幕上的其他位置时如何防止按钮失去焦点?