简体   繁体   English

通用论证方法? 超

[英]Generic argument method ? super

Why can NOT be added a new Object into a List if with this type is supposed to be able to add any supertype of Apple? 如果应该使用此类型可以添加Apple的任何超类型,为什么不能将新对象添加到列表中?

import java.util.List;
import java.util.ArrayList;
class Apple{}
public class Macintosh extends Apple {
    public static void main(String[] munch){
        List<Apple> a = new ArrayList<Apple>();
        basket(a);
    }
    static void basket(List<? super Apple> list){ list.add(new Object());}
}

If we change argument to List list, of course it works :s 如果我们将参数更改为列表列表,则当然可以使用:s


class Animal{}
class Dog extends Animal{}
class Cat extends Animal{}
public class Mixer<A extends Animal>{
    public <C extends Cat> Mixer<? super Dog> useMe(A a, C c){
        return new Mixer<Animal>();
    }
}

Why can we use Mixer in return time if the compiler in the case before didn't know about the Class of the object, now is because of is a class ?¿? 如果以前情况下的编译器不知道对象的Class,现在是因为是class,为什么还要在返回时间中使用Mixer?

You are trying to add to a List of Apples something that is not an Apple (Object is not a sublcass of Apple). 您试图将非苹果(对象不是苹果的子类)添加到苹果列表中。 Hence, the compilation error. 因此,编译错误。

You cannot add anything other than Apple and its subtypes to a List<? super Apple> 除了Apple及其子类型,您不能将其他任何内容添加到List<? super Apple> List<? super Apple> , because the ? List<? super Apple> ,因为? means 'some type' not 'any type'. 表示“某种类型”而不是“任何类型”。 It is a list of instances of some type that is either Apple or a supertype of Apple, and there is no way of knowing which exact type the ? 它是Apple或Apple的超类型的某种类型的实例的列表,并且无法知道哪个确切类型? means. 手段。

I'd suggest avoiding these constraints if you can, they don't help very often and they can easily lead to confusion. 我建议,如果可以的话,请避免使用这些限制,它们不会经常帮助您,并且很容易导致混乱。

As noted by others, wildcard types are existentially quantified types, not universally quantified. 正如其他人所指出的,通配符类型是存在量化类型,而不是普遍量化类型。 This means that, when using a variable of a type with wildcards, you can assign any matching type you wish when you are writing to it, but you cannot assume any particular type when you read from the variable. 这意味着,当使用带通配符的类型的变量时,可以在写入时分配希望的任何匹配类型,但是从变量中读取时不能假定任何特定类型。 When writing, you control the choice, but when reading, others choose it for you. 在写作时,您可以控制选择,但在阅读时,其他人会为您选择。

More Detailes 更多细节

  • You have full control when writing. 您在编写时拥有完全控制权。 The return value of a method is written to inside its body, in a return statement. 方法的返回值在return语句中写入其主体内部。 Its parameters are written to where you invoke the method. 它的参数被写入调用方法的位置。 You can happily assign a particular type to a wildcard return statement or pass a particular type to a wildcard method parameter. 您可以愉快地将特定类型分配给通配符return语句,或将特定类型传递给通配符方法参数。

  • The choice is forced upon you when reading. 阅读时会迫使您选择。 The return value of a method is read where you invoke the method. 在调用方法的地方读取方法的返回值。 Its parameters are read inside its body, where you define the method. 在其内部定义方法的位置读取其参数。 You face difficulties inside basket() when you try to use the passed list . 当您尝试使用传递的list时,您会在basket()内部遇到困难。

If we change argument to List list, of course it works :s 如果我们将参数更改为列表列表,则当然可以使用:s

That's a totally different story. 那是完全不同的故事。 List is a raw type. List是原始类型。 As you discovered yourself, you can do unsafe things, like adding an Orange or any other Object to a List<Apple> if you use raw types. 当您发现自己时,可以做一些不安全的事情,例如如果使用原始类型,则将Orange或任何其他ObjectList<Apple> Java supports raw types mostly for historical reasons like backward compatibility. Java支持原始类型主要是出于历史原因,例如向后兼容。 They are unsound by design. 他们是设计不健全的。 If you use raw types in this fashion you are likely to get a ClassCastException s later: 如果您以这种方式使用原始类型, ClassCastException稍后可能会收到ClassCastException

    List<Apple> a = new ArrayList<Apple>();
    basket(a);
    for (Apple apple : a) {     // Is not assignable to Apple, throws ClassCastException
        System.out.println(apple);
    }

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

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