泛型较低的未绑定vs较高有界通配符 [英] Generic lower unbound vs upper bounded wildcards

查看:139
本文介绍了泛型较低的未绑定vs较高有界通配符的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

  import java.util.List; 
import java.util.ArrayList;

接口Canine {}
类Dog实现Canine {}
公共类Collie延伸Dog {
public static void main(String [] args){
列出<狗> d = new ArrayList< Dog>();
列表< Collie> c = new ArrayList< Collie>();
d.add(new Collie());
c.add(new Collie());
do1(d); DO1(C);
do2(d); DO2(C);
}
static void do1(List< ;? extends Dog> d2){
d2.add(new Collie());
System.out.print(d2.size());
}
static void do2(List< ;? super collie> c2){
c2.add(new Collie());
System.out.print(c2.size());






$ b

这个问题的答案告诉我们,当一个方法需要通配类型典型值,可以访问或修改集合,但不能同时包含两者。 (Kathy and Bert)

当一个方法采用通配类型typ时,这个集合可以被访问或修改,而不是'?



据我所知,
方法do1有 List< ;?延伸狗> d2 因此只能访问d2但不能修改。
方法d2有 List <?超级大牧羊犬> c2 所以c2可以被访问和修改,并且没有编译错误。



通用指南

解决方案


这个问题的答案告诉我们,当方法采用通配符类型时,可以访问或修改集合,但不能同时采用这两种集合。 (凯西和伯特)


这是一个公平的第一个近似值,但不完全正确。更正确的是:



您只能将null添加到集合<?扩展Dog> ,因为它的add方法的参数是?延伸狗。无论何时调用一个方法,都必须传递属于声明参数类型的子类型的参数;但对于参数类型?扩展Dog ,如果表达式为 null ,编译器只能确定参数是兼容类型。但是,您当然可以通过调用 clear() remove(Object)来修改集合。



另一方面,如果您从 Collection <?>中读取数据?超级狗> ,它的迭代器的返回类型是?超级狗。也就是说,它将返回属于某个未知超类型 Dog 的子类型的对象。但不同的是,Collection可以是 Collection< Object> ,其中只包含 String 的实例。因此,

  for(Dog d:collection){...} //不会编译


$ b

所以我们唯一知道的是Object的实例被返回,即迭代这个Collection的唯一类型正确的方法是 p>

  for(Object o:collection){...} 

但是可以从集合中读取,你只是不知道你会得到什么类型的对象。



<我们可以很容易地将这个观察推广到:给定

  class G< T> {...} 

  G< ;?延伸东西> G; 

我们只能将null传递给声明类型为 T ,但我们可以调用返回类型为 T 的方法,并为结果指定一个类型为 Something

另一方面,对于

  G <?超级东西> G; 

我们可以传递任何类型的表达式 Something 到声明类型为 T 的方法参数,我们可以调用返回类型为 T 的方法,但只将结果赋值给一个 Object 类型的变量。

总之,通配符类型的使用限制仅取决于表单的方法声明,而不是方法的作用。


import java.util.List;
import java.util.ArrayList;

interface Canine {}
class Dog implements Canine {}
public class Collie extends Dog {
    public static void main(String[] args){
        List<Dog> d = new ArrayList<Dog>();
        List<Collie> c = new ArrayList<Collie>();
        d.add(new Collie());
        c.add(new Collie());
        do1(d); do1(c);
        do2(d); do2(c);
    }
    static void do1(List<? extends Dog> d2){
        d2.add(new Collie());
        System.out.print(d2.size());
    }
    static void do2(List<? super Collie> c2){
        c2.add(new Collie());
        System.out.print(c2.size());
    }
}

The answer for this question tell that when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both. (Kathy and Bert)

What does it mean 'when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both' ?

As far as I know, The method do1 has List<? extends Dog> d2 so d2 only can be accessed but not modified. The method d2 has List<? super Collie> c2 so c2 can be accessed and modified and there is no compilation error.

Generic guidelines

解决方案

The answer for this question tell that when a method takes a wildcard generic typ, the collection can be accessed or modified, but not both. (Kathy and Bert)

That's a fair first approximation, but not quite correct. More correct would be:

You can only add null to a Collection<? extends Dog> because its add method takes an argument of ? extends Dog. Whenever you invoke a method, you must pass parameters that are of a subtype of the declared parameter type; but for the parameter type ? extends Dog, the compiler can only be sure that the argument is of compatible type if the expression is null. However, you can of course modify the collection by calling clear() or remove(Object).

On the other hand, if you read from a Collection<? super Dog>, its iterator has return type ? super Dog. That is, it will return objects that are a subtype of some unknown supertype of Dog. But differently, the Collection could be a Collection<Object> containing only instances of String. Therefore

for (Dog d : collection) { ... } // does not compile

so the only thing we know is that instances of Object are returned, i.e. the only type-correct way of iterating such a Collection is

for (Object o : collection) { ... }

but it is possible to read from a collection, you just don't know what types of objects you will get.

We can easily generalize that observation to: Given

class G<T> { ... }

and

G<? extends Something> g;

we can only pass null to method parameters with declared type T, but we can invoke methods with return type T, and assign the result a variable of type Something.

On the other hand, for

G<? super Something> g;

we can pass any expression of type Something to method parameters with declared type T, and we can invoke methods with return type T, but only assign the result to a variable of type Object.

To summarize, the restrictions on the use of wildcard types only depend on the form of the method declarations, not on what the methods do.

这篇关于泛型较低的未绑定vs较高有界通配符的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆