Java <;之间的差异;?超级T>;以及<;?扩展T>;在爪哇
Java <;之间的差异;?超级T>;以及<;?扩展T>;在爪哇,java,generics,collections,Java,Generics,Collections,Listsuper是一个下限,extends是一个上限 根据: 解决方法是使用一种 我们尚未看到的有界通配符: 具有下限的通配符。这个 语法?super T表示一个未知数 是T(或T)的超类型的类型 自身;记住,超类型 关系是自反的)。它是双重的 有界通配符中的一个 使用,我们在哪里使用?延伸到 表示一个未知类型,该类型是 T亚型 扩展 使用的List的通配符声明扩展了只能从集合中获取的。你不能把它放进去。另外,虽然super同时允许get和put,但是get期间的返回类型是?super T通用
Listsuper是一个下限,extends是一个上限
根据:
解决方法是使用一种
我们尚未看到的有界通配符:
具有下限的通配符。这个
语法?super T表示一个未知数
是T(或T)的超类型的类型
自身;记住,超类型
关系是自反的)。它是双重的
有界通配符中的一个
使用,我们在哪里使用?延伸到
表示一个未知类型,该类型是
T亚型
扩展
使用的List的通配符声明扩展了只能从集合中获取的。你不能把它放进去。另外,虽然super同时允许get和put,但是get期间的返回类型是?super T通用通配符针对两个主要需求:
从通用集合中读取
插入到泛型集合中
使用通用通配符定义集合(变量)有三种方法。这些是:
List<?> listUknown = new ArrayList<A>();
List<? extends A> listUknown = new ArrayList<A>();
List<? super A> listUknown = new ArrayList<A>();
List listUknown=new ArrayList想象一下拥有这个层次结构
1.延伸
通过写作
List<? extends C2> list;
List<? super C2> list;
对于每种可能的情况,我们都有一组“可存储”类型:这里用图形表示7(红色)组
正如您所看到的,并不是每个案例都有一种常见的安全类型:
- 不能
list.add(new C2(){})因为它可能是list=new ArrayList()代码>
- 不能
list.add(newd1(){})因为它可能是list=new ArrayList()代码>
等等
2.超级的
通过写作
List<? extends C2> list;
List<? super C2> list;
对于每种可能的情况,我们都有一组“可存储”类型:这里用图形表示7(红色)组
如您所见,这里我们有七种常见的保险类型:C2
,D1
,D2
,E1
,E2
,E3
,E4
- 您可以
list.add(newC2(){})代码>因为,无论我们引用的是哪种列表,C2
都是允许的
- 您可以
list.add(newd1(){})代码>因为,无论我们引用的是哪种列表,D1
都是允许的
等等。您可能注意到,这些类型对应于从typeC2
开始的层次结构
笔记
如果您希望进行一些测试,这里是完整的层次结构
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{}
我喜欢来自@Bert F的答案,但这是我的大脑所看到的
我手里拿着一个X。如果我想将我的X写入一个列表,该列表需要是一个X列表,或者是一个我的X在写入时可以向上转换的事物列表,即X的任何超类
List<? super X>
List基于我想解释一下我的理解
假设我们有三个班级作为
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.
让我们再试一次
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)
现在,让我们尝试在水果扩展列表中设置一些对象
Fruit fruit = fruitExtendedList.get(position)
//This is valid as it can only return Fruit or its subclass.
添加水果对象
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.
添加瓜对象
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.
最后,让我们尝试添加西瓜对象
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.
但是等一下如果有人决定做一种新型的柠檬怎么办呢
现在水果扩展列表可以是水果、甜瓜、西瓜或腌菜的列表
那么,我们的声明
fruitExtendedList.add(new WaterMelon())
也无效
基本上,我们可以说,我们不能将任何内容写入到一个扩展列表中。
这总结了List这里最让人困惑的是,无论我们指定什么类型的限制,赋值都只能以一种方式工作:
baseClassInstance = derivedClassInstance;
您可能会认为整数扩展了数字
,而整数
在使用extends和super时将充当
通配符在方法参数中最有用。它们允许方法接口具有必要的灵活性
人们经常混淆何时使用extends和何时使用super-bounds。经验法则是“拿-放”原则。如果您从参数化容器中获取了一些内容,请使用extends
int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
total += v.getFuel();
}
return total;}
int totalFuel(List您可以浏览上面的所有答案,以了解为什么.add()
仅限于'
,'将项目添加到列表中:
- 列表<?扩展X>不允许在列表中添加任何内容,除了
null
`List<? super Number> listvar;
列表<?超级X>允许添加任何X(X或其子类型)或null
正在从列表中获取项目:
- 当您从列表<?扩展X>中获取项目时,可以将其分配给X类型的变量或X的任何超类型,包括对象
- 从列表<?super X>中获取项目时,只能将其分配给
对象
类型的变量
一些例子:
List<? extends Number> list1 = new ArrayList<Integer>();
list1.add(null); //OK
Number n = list1.get(0); //OK
Serializable s = list1.get(0); //OK
Object o = list1.get(0); //OK
list1.add(2.3); //ERROR
list1.add(5); //ERROR
list1.add(new Object()); //ERROR
Integer i = list1.get(0); //ERROR
List投赞成票的答案涵盖了很多方面的细节。不过,我会尝试用不同的方式回答这个问题
有2件事我们需要考虑,
1.分配给列表变量
List示例,
遗传顺序假定为O>S>T>U>V
使用扩展关键字,
正确:
但为什么会出现错误呢?
让我们看看列表对象初始化的可能性
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
但为什么在上述两种情况下会出现错误呢?
我们可以使用Object.add(new T());仅限于以下可能性
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
List我想将差异可视化。假设我们有:
class A { }
class B extends A { }
class C extends B { }
List@BertF,解释得很清楚,至少比Oracle博士的解释要好3405691582倍。我已经得出这个答案好几次了。我想我可以不止一次投票。你知道你是第一名吗?@Bert F'我在学习泛型之前喜欢java。@Danon更像那篇文章是这个答案的副本。这个answ呃是从2010年开始的,那个博客是从
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.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
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.
melonSuperList.add(new WaterMelon())
//This is also valid because of same reason as adding Melon
baseClassInstance = derivedClassInstance;
class Holder<T> {
T v;
T get() { return v; }
void set(T n) { v=n; }
}
class A {
public static void main(String[]args) {
Holder<? extends Number> he = new Holder();
Holder<? super Number> hs = new Holder();
Integer i;
Number n;
Object o;
// Producer Super: always gives an error except
// when consumer expects just Object
i = hs.get(); // <? super Number> cannot be converted to Integer
n = hs.get(); // <? super Number> cannot be converted to Number
// <? super Number> cannot be converted to ... (but
// there is no class between Number and Object)
o = hs.get();
// Consumer Super
hs.set(i);
hs.set(n);
hs.set(o); // Object cannot be converted to <? super Number>
// Producer Extends
i = he.get(); // <? extends Number> cannot be converted to Integer
n = he.get();
o = he.get();
// Consumer Extends: always gives an error
he.set(i); // Integer cannot be converted to <? extends Number>
he.set(n); // Number cannot be converted to <? extends Number>
he.set(o); // Object cannot be converted to <? extends Number>
}
}
int totalFuel(List<? extends Vehicle> list) {
int total = 0;
for(Vehicle v : list) {
total += v.getFuel();
}
return total;}
int totalValue(Valuer<? super Vehicle> valuer) {
int total = 0;
for(Vehicle v : vehicles) {
total += valuer.evaluate(v);
}
return total;}
List<? extends Number> list1 = new ArrayList<Integer>();
list1.add(null); //OK
Number n = list1.get(0); //OK
Serializable s = list1.get(0); //OK
Object o = list1.get(0); //OK
list1.add(2.3); //ERROR
list1.add(5); //ERROR
list1.add(new Object()); //ERROR
Integer i = list1.get(0); //ERROR
List<? super Number> list2 = new ArrayList<Number>();
list2.add(null); //OK
list2.add(2.3); //OK
list2.add(5); //OK
Object o = list2.get(0); //OK
list2.add(new Object()); //ERROR
Number n = list2.get(0); //ERROR
Serializable s = list2.get(0); //ERROR
Integer i = list2.get(0); //ERROR
`List<? extends X> listvar;`
`List<? super Number> listvar;
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
List<? extends T> Object = new List<S>();
List<? extends T> Object = new List<O>();
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
List<? super T> Object = new List<U>();
List<? super T> Object = new List<V>();
Object.add(new T()); //error
List<? extends T> Object = new List<T>();
List<? extends T> Object = new List<U>();
List<? extends T> Object = new List<V>();
List<? extends T> Object = new List<T>();
Object.add(new T()); // compiles fine without error
Object.add(new U()); // compiles fine without error
Object.add(new V()); // compiles fine without error
Object.add(new S()); // error
Object.add(new O()); // error
List<? super T> Object = new List<T>();
List<? super T> Object = new List<S>();
List<? super T> Object = new List<O>();
class A { }
class B extends A { }
class C extends B { }
|-------------------------|-------------------|---------------------------------|
| wildcard | get | assign |
|-------------------------|-------------------|---------------------------------|
| List<? extends C> | A B C | List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends B> | A B | List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
| List<? extends A> | A | List<A> List<B> List<C> |
|-------------------------|-------------------|---------------------------------|
|-------------------------|-------------------|-------------------------------------------|
| wildcard | add | assign |
|-------------------------|-------------------|-------------------------------------------|
| List<? super C> | C | List<Object> List<A> List<B> List<C> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super B> | B C | List<Object> List<A> List<B> |
|-------------------------|-------------------|-------------------------------------------|
| List<? super A> | A B C | List<Object> List<A> |
|-------------------------|-------------------|-------------------------------------------|