简体   繁体   English

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

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

I don't get the actual practical use case of the wildcard character ?我不了解通配符的实际用例? in Java, when using it with extends or super .在 Java 中,当它与extendssuper一起使用时。

The official Oracle Java documentation shows an example of adding numbers to a list and sum them up:官方 Oracle Java 文档展示了一个将数字添加到列表并求和的示例:

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

From my understanding List<? extends Number> list根据我的理解List<? extends Number> list List<? extends Number> list does not mean "a list of instances of Number objects and objects of possible sub-classes of Number" but instead "a list of objects of a single type, which have to be or extend the type Number". List<? extends Number> list并不意味着“Number 对象的实例列表和 Number 的可能子类的对象”,而是“单一类型的对象列表,这些对象必须是或扩展 Number 类型”。 That's all fine.没关系。

Until I tried this code:直到我尝试这段代码:

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

The instances can be added to the Number list through an implicit upcast to number references.可以通过对数字引用的隐式向上转换将实例添加到数字列表中。 And that list of numbers can then be used with the sumOfList method as shown above.然后可以将该数字列表与 sumOfList 方法一起使用,如上所示。 But the elements would not be of a single type.但元素不会是单一类型。 So why would anyone use extends with ?那么为什么有人会使用extends with ? anyways?无论如何?

The other thing that I am not getting is the use of the wildcard character with super.我没有得到的另一件事是在 super 中使用通配符。 It is fine, that you can define the lower bound of a type.很好,您可以定义类型的下限。 The offical Oracle documentation shows this example:官方 Oracle 文档显示了这个例子:

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

Thing is, this works great for a simple thing like adding numbers to a list.事实是,这对于向列表中添加数字这样的简单操作非常有效。 But the code shown also works with lists like this:但是显示的代码也适用于这样的列表:

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

So as long as one would call methods, that would do anything useful with actual numbers like - I dunno - arithmetical operations the code would probably work fine.因此,只要调用方法,它就会对实际数字做任何有用的事情,比如——我不知道——算术运算,代码可能会正常工作。 But when it comes to the John Doe entry, code meant for numbers would fail.但是当涉及到 John Doe 条目时,用于数字的代码会失败。

So can anyone clarify the actual practical use of the extends and super keywords in combination with the ?那么任何人都可以阐明extendssuper关键字与 ? 结合的实际用途? operator?操作员?

So why would anyone use extends with ?那么为什么有人会使用extends with ? anyways?无论如何?

Because you may not have a List<Number> to pass to it.因为您可能没有List<Number>传递给它。 For example, you can pass a List<Integer> , a List<BigInteger> etc to sumOfList .例如,您可以将List<Integer>List<BigInteger>等传递给sumOfList

If you hadn't declared it as accepting a List<? extends Number>如果您没有将其声明为接受List<? extends Number> List<? extends Number> , but instead as accepting a List<Number> , you could only pass a List<Number> to it - List<Integer> isn't a subtype of List<Number> . List<? extends Number> ,但是作为接受List<Number> ,您只能将List<Number>传递给它 - List<Integer>不是List<Number>的子类型。


In terms of the addNumbers method: you simply need some kind of List to which it is safe to add instances of Integer (or subtypes [of which there are none, because it is final], or null ).addNumbers方法而言:您只需要某种类型的List ,它可以安全地添加Integer的实例(或子类型 [其中没有,因为它是最终的],或null )。

That's all List<? super Integer>这就是全部List<? super Integer> List<? super Integer> means: it's safe to add instances of Integer to that. List<? super Integer>表示:可以安全地将Integer的实例添加到其中。

It's safe to pass a List<Object> to that method, because all Integer s are Object s, so it's safe to add Integer s to that list.List<Object>传递给该方法是安全的,因为所有Integer都是Object ,因此将Integer添加到该列表是安全的。

Again, if you'd declared the method as accepting a List<Object> (or a List<Integer> ), that would be all you could pass to it: a List<Object> (or a List<Integer> , respectively).同样,如果您将该方法声明为接受List<Object> (或List<Integer> ),那么您可以传递给它的就是这些:分别是List<Object> (或List<Integer> ) . You couldn't pass it, say, a List<Number> .你不能传递它,比如说,一个List<Number>


So can anyone clarify the actual practical use of the extends and super keywords in combination with the ?那么任何人都可以阐明extendssuper关键字与 ? 结合的实际用途? operator?操作员?

The practical use of wildcards is to increase the flexibility of API methods , as illustrated above: it allows you to declare a single method that takes a range of related types as inputs.通配符的实际用途是增加 API 方法的灵活性,如上图所示:它允许您声明一个方法,该方法将一系列相关类型作为输入。

You can also use wildcards in outputs, but this should be avoided, because the wildcard ends up in the type of the value at the call site, and just generally hangs around looking messy and confusing.您还可以在输出中使用通配符,但应该避免这种情况,因为通配符最终会出现在调用站点的值类型中,并且通常看起来杂乱无章。

1. So why would anyone use extends with? 1. 那么为什么有人会使用 extends with 呢? anyways?无论如何?

We can't perform write or delete operations when wildcards are used as Unbounded like "List<?>", because the compiler can't know what type it is, like:当像“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. So can anyone clarify the actual practical use of the extends and super keywords in combination with the? 2.那么谁能说清楚extends和super关键字结合the的实际用途呢? operator?操作员?

It is a good combination of using some design patterns and principles, the most simple one that comes to my mind is using it with the 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
}

That is a good way of explicit showing that if you have to iterate through workers, you only want them to be the ones that can sleep.这是一个很好的方式来明确表明,如果你必须遍历工人,你只希望他们成为可以睡觉的人。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM