Javagenerics – ArrayList初始化

众所周知,arraylist init。 应该是这样的

ArrayList a = new ArrayList(); ArrayList a = new ArrayList(); // compile-time error 

所以,为什么java允许这些?

 1. ArrayList a1 = new ArrayList(); 2. ArrayList a2 = new ArrayList(); 

那么,如果他们是正确的,为什么不允许这些呢?

 1. a1.add(3); 2. a2.add(3); 

编译器消息是:类型ArrayList中的方法add(int,capture#1-of?extends 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分配给List类型的引用,因为List允许除Integer其他数字类型。 如果您被允许这样做,将允许以下内容:

 List numbers = new ArrayList(); numbers.add(1.1); // add a double List ints = numbers; Integer fail = ints.get(0); // ClassCastException! 

List类型保证它包含的任何内容都是Integer 。 这就是为什么你可以在没有强制转换的情况下从中获取Integer 。 如您所见,如果编译器允许将另一个类型的List (例如Number分配给List ,那么保证将被破坏。

List分配给类型的引用,例如ListList List是合法的,因为? 表示“给定类型的某个未知子类型”(其中类型是仅在?的情况下为Object ,在? extends Number的情况下为? extends Number )。

既然? 表示您不知道 List将接受哪种特定类型的对象,添加除null任何内容都是不合法的。 但是,您可以从中检索任何对象,这是使用? extends X的目的? extends X ? extends X有界通配符类型。 请注意,对于一个相反的情况是正确的? super X ? super X有界通配符类型… List List是“一个至少是Integer超类型的未知类型的列表”。 虽然您不确切知道它的List类型(可能是ListListList ),但您确实知道无论它是什么,都可以添加一个Integer

最后, new ArrayList()是不合法的,因为当您创建像ArrayList这样的参数化类的实例时,您必须提供特定的类型参数。 你真的可以在你的例子中使用任何东西( ObjectFoo ,它没关系),因为你将永远无法向它添加任何东西,因为你将它直接分配给ArrayList引用。

关键在于引用和实例之间的差异以及引用可以承诺的内容以及实例可以真正做什么。

 ArrayList a = new ArrayList(); 

这里a是对特定类型实例的引用 – 恰好是A的数组列表。 更明确地, a是对将接受A s并将产生A s的数组列表的引用。 new ArrayList()A s的数组列表的实例,即一个接受A s并将产生A s的数组列表。

 ArrayList a = new ArrayList(); 

这里, a是对Integers数组列表的引用,即完全是一个可以接受Integer并将生成Integer的数组列表。 它不能指向Number s的数组列表。 Number的数组列表不能满足ArrayList a所有承诺(即Number的数组列表可能产生不是Integer的对象,即使它是空的然后)。

 ArrayList a = new ArrayList(); 

在这里,声明a表示将完全引用Number s的数组列表,即,恰好是一个将接受Number s的数组列表并将生成Number s。 它不能指向Integer的数组列表,因为a的类型声明表示a可以接受任何Number ,但是Integer的数组列表不能接受任何Number ,它只能接受Integer s。

 ArrayList a= new ArrayList(); 

这里a对类型族的 (通用)引用,而不是对特定类型的引用。 它可以指向属于该系列成员的任何列表。 然而,这个很好的灵活引用的权衡是,如果它是特定于类型的引用(例如非generics),它们不能保证它可能具有的所有function。 在这种情况下, a是对将生成 Object的数组列表的引用。 但是 ,与特定于类型的列表引用不同,此引用不能接受任何Object 。 (即不是每个类型的成员都可以指向可以接受任何Object ,例如, Integer的数组列表只能接受Integer 。)

 ArrayList a = new ArrayList(); 

同样, a是对类型族的引用(而不是单个特定类型)。 由于通配符使用super ,此列表引用可以接受Integer ,但它不能生成Integer 。 换句话说,我们知道可以指向的类型族中的任何一个成员都可以接受Integer 。 但是,并非该家族的每个成员都能产生Integer

PECS – 生产者extends ,消费者super – 这个助记符可以帮助您记住使用extends意味着generics类型可以生成特定类型(但不能接受它)。 使用super意味着generics类型可以使用 (接受)特定类型(但不能生成它)。

 ArrayList> a 

一个数组列表,其中包含对作为数组列表类型族成员的任何列表的引用。

 = new ArrayList>(); // correct 

数组列表的实例,其中包含对作为数组列表类型族成员的任何列表的引用。

 ArrayList a 

对任何数组列表的引用(数组列表类型系列的成员)。

 = new ArrayList() 

ArrayListArrayList组列表类型系列中的任何类型,但您只能实例化特定类型。


另请参见如何添加到列表<? 扩展Number>数据结构?

你有奇怪的期望。 如果你给出了引导他们的论据链,我们可能会发现它们中的缺陷。 事实上,我只能简单介绍一下generics,希望触及你可能误解的几点。

ArrayList ArrayList是一个ArrayList,其类型参数已知为Object或其子类型。 (是的,类型边界中的扩展具有除直接子类之外的含义)。 由于只有引用类型可以是类型参数,因此实际上它等同于ArrayList

也就是说,您可以将ArrayList放入使用ArrayList声明的变量中。 这就是a1.add(3)是编译时错误的原因。 a1的声明类型允许a1ArrayList ,不能添加任何Integer

显然, ArrayList不是很有用,因为你只能在其中插入null。 这可能是Java Spec 禁止它的原因:

如果类实例创建表达式中使用的任何类型参数是通配符类型参数,那么这是编译时错误

相反, ArrayList>是function数据类型。 您可以将各种ArrayLists添加到其中,然后检索它们。 由于ArrayList包含不是通配符类型,因此上述规则不适用。

很多这与多态性有关。 分配时

 X = new Y(); 

X可以比Y更“特异”,但不是相反。 X只是你正在访问Y的句柄,Y是真正实例化的东西,

这里收到错误,因为Integer是一个Number,但Number不是Integer。

 ArrayList a = new ArrayList(); // compile-time error 

因此,您调用的任何X方法必须对Y有效。由于X更一般地它可能共享一些但不是所有Y的方法。 但是,任何给出的论点必须对Y有效。

在使用add的示例中,int(小i)不是有效的Object或Integer。

 ArrayList a = new ArrayList(); 

这不好,因为你实际上无法实例化包含?的数组列表。 你可以声明一个,然后在new ArrayList();

想想? 至于意思是"unknown" 。 因此, "ArrayList"是指“一个未知类型(或只要它)扩展Object”。 因此,需要说的是, arrayList.add(3)会把你知道的东西放到一个未知的地方。 即’遗忘’。

 ArrayList a = new ArrayList(); 

因为Number是Integer的超类这一事实不起作用并不意味着ListList的超类。 generics在编译期间被删除,并且在运行时不存在,因此无法实现集合的父子关系:仅删除有关元素类型的信息。

 ArrayList a1 = new ArrayList(); a1.add(3); 

我无法解释为什么它不起作用。 这真的很奇怪,但这是事实。 真的语法 主要用于方法的返回值。 即使在此示例中, Object o = a1.get(0)也是有效的。

 ArrayList a = new ArrayList() 

这不起作用,因为您无法实例化未知类型的列表…