众所周知,arraylist是init。应该是这样的
ArrayList<A> a = new ArrayList<A>();
ArrayList<Integer> a = new ArrayList<Number>(); // compile-time error
那么,为什么Java允许这些?
1. ArrayList<? extends Object> a1 = new ArrayList<Object>();
2. ArrayList<?> a2 = new ArrayList<Integer>();
那么,如果它们是正确的,为什么不允许这些?
1. a1.add(3);
2. a2.add(3);
编译器消息是:ArrayList类型中的方法add(int,capture#1-of?extended Object)不适用于参数(int)
更一般
1. a1.add(null e);
2. a2.add(? e);
我读到了有关此事,但很高兴收到您的来信。谢谢
另一个有趣的地方是:
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
最佳答案
您不能将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!
List<Integer>
类型可以保证它包含的任何内容都是Integer
。这就是为什么您可以不进行强制转换就从其中获取Integer
的原因。如您所见,如果编译器允许将其他类型的List
(例如Number
)分配给List<Integer>
,则保证会被破坏。将
List<Integer>
分配给诸如List<?>
或List<? extends Number>
之类的类型的引用是合法的,因为?
表示“给定类型的某些未知子类型”(对于Object
而言,类型是?
;对于Number
而言,类型是? extends Number
)。由于
?
表示您不知道List
将接受哪种特定类型的对象,因此除了null
之外,都不能添加任何其他对象。但是,允许您从其中检索任何对象,这是使用? extends X
限制通配符类型的目的。请注意,对于? super X
有界通配符类型而言,情况恰恰相反... List<? super Integer>
是“至少是Integer
的父类(super class)型的某种未知类型的列表”。尽管您不确定确切的List
类型(可以是List<Integer>
,List<Number>
,List<Object>
),但您确实知道无论是哪种类型,都可以将Integer
添加到其中。最后,
new ArrayList<?>()
是不合法的,因为当您创建像ArrayList
这样的参数化类的实例时,必须提供一个特定的类型参数。您可以在示例中使用任何内容(Object
,Foo
都没有关系),因为除了null
之外,您将无法再添加其他任何内容,因为您是直接将其分配给ArrayList<?>
引用。