何时使用生产者和消费者逻辑/通配符JAVA

时间:2018-06-06 12:45:41

标签: 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>无法就地更改(数字是不可变的),但编译器可以使用它。

更新:
显然,我并没有正确理解&#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。

2 个答案:

答案 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>

相关问题