众所周知,arraylist init.应该是这样的
ArrayList<A> a = new ArrayList<A>();
ArrayList<Integer> a = new ArrayList<Number>(); // compile-time error
Run Code Online (Sandbox Code Playgroud)
所以,为什么java允许这些?
1. ArrayList<? extends Object> a1 = new ArrayList<Object>();
2. ArrayList<?> a2 = new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)
那么,如果他们是正确的,为什么不允许这些呢?
1. a1.add(3);
2. a2.add(3);
Run Code Online (Sandbox Code Playgroud)
编译器消息是:类型ArrayList中的方法add(int,capture#1-of?extends Object)不适用于参数(int)
更一般
1. a1.add(null e);
2. a2.add(? e);
Run Code Online (Sandbox Code Playgroud)
我读到了这个,但很高兴收到你的来信.谢谢
另一个有趣的观点是:
ArrayList<ArrayList<?>> a = new ArrayList<ArrayList<?>>(); // correct
ArrayList<?> a = new ArrayList<?>(); // wrong. I know it's reason but I have some
question in my mind that mentioned above
Run Code Online (Sandbox Code Playgroud)
Col*_*inD 13
您不能将a指定给List<Number>
类型的引用,List<Integer>
因为它List<Number>
允许除了以外的数字类型Integer
.如果您被允许这样做,将允许以下内容:
List<Number> numbers = new ArrayList<Number>();
numbers.add(1.1); // add a double
List<Integer> ints = numbers;
Integer fail = ints.get(0); // ClassCastException!
Run Code Online (Sandbox Code Playgroud)
该类型List<Integer>
保证其中包含的任何内容都是一个Integer
.这就是为什么你可以在Integer
没有施法的情况下获得它的原因.正如您所看到的,如果编译器允许List
另一种类型(如Number
分配给List<Integer>
该保证)将被破坏.
分配List<Integer>
到例如类型的基准List<?>
或List<? extends Number>
是合法的,因为?
装置(其中的类型是"给定的类型的一些未知的子类型" Object
中的只是的情况下?
和Number
在的情况下? extends Number
).
由于?
表示您不知道List
将接受哪种特定类型的对象,因此添加除此之外的任何内容都是不合法的null
.但是,您可以从中检索任何对象,这是使用有? extends X
界通配符类型的目的.请注意,对于有? super X
界通配符类型,情况正好相反... a List<? super Integer>
是"某个未知类型的列表,至少是一个超类型Integer
".虽然你不知道到底是什么类型的List
是(可能是List<Integer>
,List<Number>
,List<Object>
)你肯定知道不管它是什么,一个Integer
可以被添加到它.
最后,这new ArrayList<?>()
是不合法的,因为当您创建类似于参数化类的实例时ArrayList
,您必须提供特定的类型参数.你可以在你的例子中使用任何东西(但是Object
,Foo
无关紧要),因为你将永远无法添加任何内容null
,因为你将它直接分配给ArrayList<?>
引用.
关键在于引用和实例之间的差异以及引用可以承诺的内容以及实例可以实际执行的操作.
ArrayList<A> a = new ArrayList<A>();
Run Code Online (Sandbox Code Playgroud)
这a
是对特定类型实例的引用 - 恰好是A
s 的数组列表.更明确地说,a
是对将接受A
s并将生成A
s 的数组列表的引用. new ArrayList<A>()
是一个A
s 数组列表的实例,即一个接受A
s并将生成A
s 的数组列表.
ArrayList<Integer> a = new ArrayList<Number>();
Run Code Online (Sandbox Code Playgroud)
这里a
是对数组列表的精确引用Integers
,即完全是一个可以接受Integer
s并将生成Integer
s 的数组列表.它不能指向Number
s 的数组列表.Number
s的数组列表不能满足所有的承诺ArrayList<Integer> a
(即Number
s 的数组列表可能产生不是Integer
s的对象,即使它是空的然后).
ArrayList<Number> a = new ArrayList<Integer>();
Run Code Online (Sandbox Code Playgroud)
在这里,声明a
说,a
将把正是数组列表Number
S,也就是说,正是将接受一个数组列表Number
S和将产生Number
秒.它不能指向数组列表Integer
S,因为类型声明a
说,a
可以接受任何Number
,但数组列表Integer
s不能接受随便什么Number
,它只能接受Integer
秒.
ArrayList<? extends Object> a= new ArrayList<Object>();
Run Code Online (Sandbox Code Playgroud)
这a
是对一系列类型的(通用)引用,而不是对特定类型的引用.它可以指向属于该系列成员的任何列表.然而,这个很好的灵活引用的权衡是,如果它是类型特定的引用(例如非泛型),它们不能承诺它可能具有的所有功能.在这种情况下,a
是对将生成 Object
s 的数组列表的引用.但是,与特定于类型的列表引用不同,此a
引用不能接受任何引用Object
.(即不是每个a
可以指向的类型的成员都可以接受任何成员Object
,例如Integer
s 的数组列表只能接受Integer
s.)
ArrayList<? super Integer> a = new ArrayList<Number>();
Run Code Online (Sandbox Code Playgroud)
同样,a
是对一类类型(而不是单一特定类型)的引用.由于通配符使用super
,此列表引用可以接受Integer
s,但它不能生成Integer
s.换句话说,我们知道可以指出的任何类型的家庭成员a
都可以接受Integer
.然而,并非该家庭的每个成员都能生产Integer
s.
PECS - 生产者extends
,消费者super
- 这个助记符可以帮助您记住使用 extends
手段,泛型类型可以生成特定类型(但不能接受它).使用super
意味着泛型类型可以使用(接受)特定类型(但不能生成它).
ArrayList<ArrayList<?>> a
Run Code Online (Sandbox Code Playgroud)
一个数组列表,其中包含对作为数组列表类型族成员的任何列表的引用.
= new ArrayList<ArrayList<?>>(); // correct
Run Code Online (Sandbox Code Playgroud)
数组列表的实例,其中包含对作为数组列表类型族成员的任何列表的引用.
ArrayList<?> a
Run Code Online (Sandbox Code Playgroud)
对任何数组列表的引用(数组列表类型系列的成员).
= new ArrayList<?>()
Run Code Online (Sandbox Code Playgroud)
ArrayList<?>
指的是数组列表类型系列中的任何类型,但您只能实例化特定类型.
归档时间: |
|
查看次数: |
101716 次 |
最近记录: |