【问题标题】:When to use a producer and consumer logic / Wildcards JAVA何时使用生产者和消费者逻辑/通配符 JAVA
【发布时间】:2018-11-16 03:51:34
【问题描述】:


有人可以帮我理解这段代码背后的逻辑吗:

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(&lt;? extends Number&gt; e) 一个数字,我认为没关系。 但是编译器说不是。为什么?
我希望 DoubleValue&lt;Number&gt;.dve -&gt; e.doubleValue() 一样,这应该是典型的消费者:我得到了价值 &lt;? extends Number&gt; 并用它做点什么。


sumOfListWorkingSuper:
sumOfListWorkingSuper 的行为也让我感到困惑。 接口DoubleValue&lt;? super Number&gt; 不能是消费者,因为&lt;? super Number&gt; 的值不能就地更改(数字是不可变的),但编译器可以接受。

更新:
显然我没有正确理解“生产者”和“消费者”的逻辑。

sumOfListNotWorking:
此方法无法编译,因为我使用:

  • List&lt;? extends Number&gt; list 作为制片人(在我取出的方法中 带有循环的列表中的值)。
  • DoubleValue&lt;? extends Number&gt; 作为消费者(在方法中我将 Number 传递给 f.dv(n)),但是当我尝试将值 Number 传递给 f 时,编译器告诉我 f 被定义为生产者(&lt;? extends Number&gt; - 有一些值Number 或它的孩子),它不能接受任何值。如果我传递给f 参数DoubleValue&lt;Integer&gt; 怎么办,那么我会尝试将Number 放在Integer 的位置——这是不可能的。发生所有这些错误是因为我定义了生产者而不是消费者。

感谢您指出消费者和生产者逻辑中的“接受”一词。

【问题讨论】:

标签: java


【解决方案1】:

List&lt;? extends Number&gt; 的意思是“我们不知道这个 List 包含什么,但不管它是什么,它都是 Number 或 Number 本身的后代。”

同样,DoubleValue&lt;? extends Number&gt; 的意思是“我们不知道这个 DoubleValue 可以接受什么来操作,但无论它接受什么,它都是 Number 或 Number 本身的后代”。

这里的相关部分是“我们不知道它接受什么”。我们不知道,所以你不能给它任何东西并期望它会被接受:因为你不知道它是否被接受。其余信息无关紧要。它在List&lt;? extends Number&gt; 中是相关的,因为至少我们知道它给出的任何元素都可以在发出后安全地转换为 Number 。但是你的 DoubleValue 类并没有给出任何东西。它只接受东西。所以所有那些“但我们知道它是它的后代”是完全没用的。

&lt;? extends Stuff&gt; 在提供对象的类上很有用。对不发物的人来说是没用的。

&lt;? super Stuff&gt; 在接受对象的类上很有用。对不接受物体的人来说是没用的。

【讨论】:

  • 我想建议您通过展示如何在代码中解决此问题来扩展您的答案(使方法通用并添加“未知”类型作为参数,例如,T)。
  • @lexicore 谢谢你的建议,但我的印象是这里没有什么可以解决的。 OP 有有效的代码,只问为什么 extends Number> 不起作用。我希望我足够清楚地解释了为什么它不起作用,并且 OP 应该坚持使用的代码。
  • 请看我的回答。 OP 可能没有明确要求它,但我认为这是一个很好的附加信息。如果您愿意将此作为您的答案,我将删除我的。
【解决方案2】:

除了@kumesana 的回答,您可以通过以下方式修复您的方法:

public static <T extends Number> void sumOfListNotWorking(
    List<? extends T> list,
    DoubleValue<? super T> f) {

    for (T n : list)
        f.dv(n);

}

您只需将通配符中的“未知”类型设为已知 (T)。

另请参阅PECS 规则。这里,list 提供物品(即它是一个生产者),f 接受物品(它是一个消费者)。所以输入list应该扩展T,输入f应该超T。这允许传递List&lt;Integer&gt;DoubleValue&lt;Number&gt;

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多