<?之间的区别 超级T>和<? 在Java中扩展T>



Answers

想象一下这个层次

1.延长

通过写作

    List<? extends C2> list;

你说list将能够引用一个类型的对象(例如),其泛型类型是C2的7 个子类型之一(包括C2 ):

  1. C2: new ArrayList<C2>(); ,(可以存储C2或子类型的对象)或
  2. D1: new ArrayList<D1>(); ,(可存储D1或子类型的对象)或
  3. D2: new ArrayList<D2>(); ,(可以存储D2或子类型的对象)或...

等等。 七种不同的情况:

    1) new ArrayList<C2>(): can store C2 D1 D2 E1 E2 E3 E4
    2) new ArrayList<D1>(): can store    D1    E1 E2  
    3) new ArrayList<D2>(): can store       D2       E3 E4
    4) new ArrayList<E1>(): can store          E1             
    5) new ArrayList<E2>(): can store             E2             
    6) new ArrayList<E3>(): can store                E3             
    7) new ArrayList<E4>(): can store                   E4             

对于每种可能的情况,我们都有一组“可存储”类型:这里用图形表示7(红色)

正如你所看到的,没有一种安全类型对于每一种情况都是常见的:

  • 你不能list.add(new C2(){}); 因为它可能是list = new ArrayList<D1>();
  • 你不能list.add(new D1(){}); 因为它可能是list = new ArrayList<D2>();

等等。

2.超级

通过写作

    List<? super C2> list;

你说list将能够引用一个类型的对象(例如),其泛型类型是C2的七个超类型之一(包括C2 ):

  • A1: new ArrayList<A1>(); ,(可存储A1或子类型的对象)或
  • A2: new ArrayList<A2>(); ,(可以存储A2或子类型的对象)或
  • A3: new ArrayList<A3>(); ,(可以存储A3或子类型的对象)或...

等等。 七种不同的情况:

    1) new ArrayList<A1>(): can store A1          B1 B2       C1 C2    D1 D2 E1 E2 E3 E4
    2) new ArrayList<A2>(): can store    A2          B2       C1 C2    D1 D2 E1 E2 E3 E4
    3) new ArrayList<A3>(): can store       A3          B3       C2 C3 D1 D2 E1 E2 E3 E4
    4) new ArrayList<A4>(): can store          A4       B3 B4    C2 C3 D1 D2 E1 E2 E3 E4
    5) new ArrayList<B2>(): can store                B2       C1 C2    D1 D2 E1 E2 E3 E4
    6) new ArrayList<B3>(): can store                   B3       C2 C3 D1 D2 E1 E2 E3 E4
    7) new ArrayList<C2>(): can store                            C2    D1 D2 E1 E2 E3 E4

对于每种可能的情况,我们都有一组“可存储”类型:这里用图形表示7(红色)

正如你所看到的,这里我们有七种安全类型 ,它们在每种情况下都是共同的: C2D1D2E1E2E3E4

  • 你可以list.add(new C2(){}); 因为无论我们引用的List是什么类型, C2都是允许的
  • 你可以list.add(new D1(){}); 因为无论我们引用的List是什么类型, D1都是允许的

等等。 您可能注意到这些类型与从C2类型开始的层次结构相对应。

笔记

这里是完整的层次结构,如果你想做一些测试

interface A1{}
interface A2{}
interface A3{}
interface A4{}

interface B1 extends A1{}
interface B2 extends A1,A2{}
interface B3 extends A3,A4{}
interface B4 extends A4{}

interface C1 extends B2{}
interface C2 extends B2,B3{}
interface C3 extends B3{}

interface D1 extends C1,C2{}
interface D2 extends C2{}

interface E1 extends D1{}
interface E2 extends D1{}
interface E3 extends D2{}
interface E4 extends D2{}
Question

List<? super T>什么区别List<? super T> List<? super T>List<? extends T> List<? extends T>

我曾经使用List<? extends T> List<? extends T> ,但它不允许我添加元素给它list.add(e) ,而List<? super T> List<? super T>




何时使用扩展和超级

通配符在方法参数中非常有用。 它们为方法接口提供了必要的灵活性。

人们常常在什么时候使用扩展以及何时使用超级界限时感到困惑。 经验法则是取得原则。 如果你从参数容器中获得某些东西,请使用extends。

int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
    total += v.getFuel();
}
return total;}

方法totalFuel从列表中获取车辆,询问他们有多少燃油,并计算总量。 如果将对象放入参数化容器中,请使用super。

int totalValue(Valuer<? super Vehicle> valuer) {
int total = 0;
for(Vehicle v : vehicles) {
    total += valuer.evaluate(v);
}
return total;}

方法totalValue将车辆置入估值器。 知道扩展边界比超级更普遍是有用的。




最新的投票答案涵盖了许多方面的细节。 但是,我会尝试以不同的方式回答这个问题。

有两件事我们需要考虑,

1.分配给列表变量

List<? extends X> listvar;

这里, X的任何列表或X的子类列表都可以分配给listvar。

List<? extends Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Integer>();

List<? super X> listvar;

这里, X的任何列表或X的超类列表都可以分配给listvar。

List<? super Number> listvar; listvar = new ArrayList<Number>(); listvar = new ArrayList<Object>();

2.对列表变量执行读取或写入操作

`List<? extends X> listvar;`

您可以使用此功能来接受方法参数中的列表,并对类型X执行任何操作(请注意:您只能从列表中读取X类型的对象 )。

`List<? super Number> listvar;

您可以使用此功能接受方法参数中的列表,并对Object类型执行任何操作,因为您只能从列表中读取Object类型的对象但是,这里还有一件事是,您可以将X类型的对象添加到列表中。







基于Bert F的回答,我想解释我的理解。

假设我们有3个类

public class Fruit{}

public class Melon extends Fruit{}

public class WaterMelon extends Melon{}

我们在这里

List<? extends Fruit> fruitExtendedList = …

//Says that I can be a list of any object as long as this object extends Fruit.

好吧,现在让我们尝试从fruitExtendedList中获取一些值

Fruit fruit = fruitExtendedList.get(position)

//This is valid as it can only return Fruit or its subclass.

再次尝试

Melon melon = fruitExtendedList.get(position)

//This is not valid because fruitExtendedList can be a list of Fruit only, it may not be 
//list of Melon or WaterMelon and in java we cannot assign sub class object to 
//super class object reference without explicitly casting it.

同样的情况

WaterMelon waterMelon = fruitExtendedList.get(position)

现在让我们尝试在fruitExtendedList中设置一些对象

添加水果对象

fruitExtendedList.add(new Fruit())

//This in not valid because as we know fruitExtendedList can be a list of any 
//object as long as this object extends Fruit. So what if it was the list of  
//WaterMelon or Melon you cannot add Fruit to the list of WaterMelon or Melon.

添加Melon对象

fruitExtendedList.add(new Melon())

//This would be valid if fruitExtendedList was the list of Fruit but it may 
//not be, as it can also be the list of WaterMelon object. So, we see an invalid 
//condition already.

最后让我们尝试添加WaterMelon对象

fruitExtendedList.add(new WaterMelon())

//Ok, we got it now we can finally write to fruitExtendedList as WaterMelon 
//can be added to the list of Fruit or Melon as any superclass reference can point 
//to its subclass object.

但请等待 ,如果有人决定让一种新型柠檬让参议员SaltyLemon说出来

public class SaltyLemon extends Lemon{}

现在fruitExtendedList可以是水果,甜瓜,水芒或咸味柠檬的列表。

所以,我们的发言

fruitExtendedList.add(new WaterMelon())

也是无效的。

基本上我们可以说我们不能写任何东西给fruitExtendedList。

这总结了List<? extends Fruit> List<? extends Fruit>

现在让我们看看

List<? super Melon> melonSuperList= …

//Says that I can be a list of anything as long as its object has super class of Melon.

现在让我们尝试从melonSuperList中获得一些价值

Fruit fruit = melonSuperList.get(position)

//This is not valid as melonSuperList can be a list of Object as in java all 
//the object extends from Object class. So, Object can be super class of Melon and 
//melonSuperList can be a list of Object type

同样,Melon,WaterMelon或任何其他物体都不能被读取。

但请注意,我们可以读取对象类型实例

Object myObject = melonSuperList.get(position)

//This is valid because Object cannot have any super class and above statement 
//can return only Fruit, Melon, WaterMelon or Object they all can be referenced by
//Object type reference.

现在,我们尝试从melonSuperList中设置一些值。

添加对象类型对象

melonSuperList.add(new Object())

//This is not valid as melonSuperList can be a list of Fruit or Melon.
//Note that Melon itself can be considered as super class of Melon.

添加水果类型对象

melonSuperList.add(new Fruit())

//This is also not valid as melonSuperList can be list of Melon

添加Melon类型对象

melonSuperList.add(new Melon())

//This is valid because melonSuperList can be list of Object, Fruit or Melon and in 
//this entire list we can add Melon type object.

添加WaterMelon类型对象

melonSuperList.add(new WaterMelon())

//This is also valid because of same reason as adding Melon

总结一下,我们可以在melonSuperList中添加Melon或其子类,并只读Object对象。




列表<? 扩展X>不允许向列表中添加任何内容。

列表<? 超X>允许添加任何是X(X或其子类)。




Links