Java中的通配符(?)有实际的实际用例吗?

Is there an actual practical usecase of the wildcard character (?) in Java?

当与 extendssuper 一起使用时,我没有得到 Java 中通配符 ? 的实际用例。

官方 Oracle Java 文档显示了一个将数字添加到列表并求和的示例:

private static double sumOfList(List<? extends Number> list) {
    double sum = 0.0;
    for (Number number : list) {
        sum += number.doubleValue();
    }
    return sum;
}

根据我的理解 List<? extends Number> list 并不意味着 “Number 对象的实例列表和 Number 的可能子 类 的对象”,而是“单一类型的对象列表,必须是或扩展类型 Number”。没关系。

直到我尝试了这段代码:

List<Number> numberList = new ArrayList<Number>();
numberList.add(Integer.valueOf(123));
numberList.add(Double.valueOf(2.34));
numberList.add(Float.valueOf(3.45f));

可以通过对数字引用的隐式向上转换将实例添加到数字列表中。然后可以将该数字列表与 sumOfList 方法一起使用,如上所示。但元素不会是单一类型。那么,为什么会有人将 extends? 一起使用呢?

我没有得到的另一件事是在 super 中使用通配符。很好,您可以定义类型的下限。 Oracle 官方文档显示了这个例子:

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

事实是,这对于向列表中添加数字这样的简单操作非常有效。但是显示的代码也适用于这样的列表:

List<Object> list = new ArrayList<Object>();
list.add(Integer.valueOf(123));
list.add(Double.valueOf(2.34));
list.add(new Person("John", "Doe"));

所以只要调用方法,它就会对实际数字做任何有用的事情,比如 - 我不知道 - 算术运算代码可能会正常工作。但是当涉及到 John Doe 条目时,用于数字的代码将失败。

那么谁能阐明extendssuper关键字结合?运算符的实际应用?

So why would anyone use extends with ? anyways?

因为您可能没有 List<Number> 可以传递给它。例如,您可以将 List<Integer>List<BigInteger> 等传递给 sumOfList.

如果您没有声明它接受 List<? extends Number>,而是接受 List<Number>,您只能将 List<Number> 传递给它 - List<Integer>不是 List<Number>.

的子类型

addNumbers 方法而言:您只需要某种 List 即可安全地向其中添加 Integer 的实例(或子类型 [其中有 none, 因为它是最终的], 或 null).

这就是全部 List<? super Integer> 的意思:可以安全地向其中添加 Integer 的实例。

List<Object> 传递给该方法是安全的,因为所有 Integer 都是 Object,因此将 Integer 添加到该列表是安全的。

同样,如果您将方法声明为接受 List<Object>(或 List<Integer>),那么您只能传递给它:List<Object>(或a List<Integer>,分别)。你不能通过它,比如说,List<Number>.


So can anyone clarify the actual practical use of the extends and super keywords in combination with the ? operator?

通配符的实际用途是增加API方法的灵活性,如上图所示:它允许你声明一个单一的方法,它接受一个范围相关类型作为输入。

您也可以在输出中使用通配符,但应该避免这种情况,因为通配符最终会出现在调用站点的值的类型中,并且通常看起来杂乱无章。

1.那么为什么有人会使用 extends with 呢?不管怎样?

像"List"这样的Unbounded使用通配符时,我们无法进行写入或删除操作,因为编译器无法知道它是什么类型,如:

    // not allowed
    public static void displayList(List<?> list) {
        list.add(1);
    }

    // allowed
    public static void displayList(List<? super Integer> list) {
        list.add(1);
    }

2。那么任何人都可以阐明 extends 和 super 关键字与 ? 结合的实际用途吗?运算符?

它很好地结合了一些设计模式和原则,我想到的最简单的是将它与 Interface Segregation Principle 一起使用。

interface Worker {
    void work();
}

interface Sleeping {
    void sleep();
}

class Human implements Worker, Sleeping {

    @Override
    public void work() {}

    @Override
    public void sleep() {}
}

class Robot implements Worker {

    @Override
    public void work() {}
}

    public static void main(String[] args) {
    Human human1 = new Human();
    Human human2 = new Human();
    List<Human> humans = List.of(human1, human2);
    displayIfSleeping(humans);

    Robot robot1 = new Robot();
    Robot robot2 = new Robot();
    List<Robot> robots = List.of(robot1, robot2);
    displayIfSleeping(robots); // error

}

public static void displayIfSleeping(List<? extends Sleeping> workers) {
    // display only workers who are sleeping
}

这是一种很好的方式,可以明确表明如果您必须遍历工作人员,您只希望他们成为可以睡觉的人。