Java 泛型 - ArrayList 初始化
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4492950/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java generics - ArrayList initialization
提问by
It is known that arraylist init. should be like this
众所周知,arraylist init. 应该是这样的
ArrayList<A> a = new ArrayList<A>();
ArrayList<Integer> a = new ArrayList<Number>(); // compile-time error
so, why does java allow these ?
那么,为什么java允许这些?
1. ArrayList<? extends Object> a1 = new ArrayList<Object>();
2. ArrayList<?> a2 = new ArrayList<Integer>();
then, if they are correct why doesn't allow these ?
那么,如果他们是正确的,为什么不允许这些?
1. a1.add(3);
2. a2.add(3);
the compiler message is : The method add(int, capture#1-of ? extends Object) in the type ArrayList is not applicable for the arguments (int)
编译器消息是: ArrayList 类型中的方法 add(int, capture#1-of ? extends Object) 不适用于参数 (int)
more general
更一般
1. a1.add(null e);
2. a2.add(? e);
I read about this but it is good to hear from you. thanks
我读过这个,但很高兴收到你的来信。谢谢
the other amusing point is :
另一个有趣的点是:
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
采纳答案by ColinD
You can't assign a List<Number>
to a reference of type List<Integer>
because List<Number>
allows types of numbers other than Integer
. If you were allowed to do that, the following would be allowed:
您不能将 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!
The type List<Integer>
is making a guarantee that anything it contains will be an Integer
. That's why you're allowed to get an Integer
out of it without casting. As you can see, if the compiler allowed a List
of another type such as Number
to be assigned to a List<Integer>
that guarantee would be broken.
该类型List<Integer>
保证它包含的任何内容都是Integer
. 这就是为什么你可以在Integer
不铸造的情况下摆脱它。如您所见,如果编译器允许将List
其他类型的Number
a 分配给 a List<Integer>
,则该保证将被破坏。
Assigning a List<Integer>
to a reference of a type such as List<?>
or List<? extends Number>
is legal because the ?
means "some unknown subtype of the given type" (where the type is Object
in the case of just ?
and Number
in the case of ? extends Number
).
将 a 分配List<Integer>
给诸如List<?>
或 之类的类型的引用List<? extends Number>
是合法的,因为这?
意味着“给定类型的某个未知子类型”(其中类型Object
在 just的情况下?
和Number
在 的情况下? extends Number
)。
Since ?
indicates that you do not knowwhat specific type of object the List
will accept, it isn't legal to add anything but null
to it. You are, however, allowed to retrieveany object from it, which is the purpose of using a ? extends X
bounded wildcard type. Note that the opposite is true for a ? super X
bounded wildcard type... a List<? super Integer>
is "a list of some unknown type that is at least a supertype of Integer
". While you don't know exactly what type of List
it is (could be List<Integer>
, List<Number>
, List<Object>
) you do know for sure that whatever it is, an Integer
can be added to it.
由于?
表示您不知道List
将接受什么特定类型的对象,因此向其添加任何内容都是不合法的null
。但是,您可以从中检索任何对象,这是使用有? extends X
界通配符类型的目的。请注意,对于有? super X
界通配符类型,情况正好相反...... aList<? super Integer>
是“一些未知类型的列表,它至少是”的超类型Integer
。虽然您不确切知道List
它是什么类型(可能是List<Integer>
, List<Number>
, List<Object>
),但您确实知道无论它是什么,Integer
都可以向其中添加an 。
Finally, new ArrayList<?>()
isn't legal because when you're creating an instance of a paramterized class like ArrayList
, you have to give a specifictype parameter. You could really use whatever in your example (Object
, Foo
, it doesn't matter) since you'll never be able to add anything but null
to it since you're assigning it directly to an ArrayList<?>
reference.
最后,这new ArrayList<?>()
是不合法的,因为当你创建一个像 参数化类的实例时ArrayList
,你必须给出一个特定的类型参数。你真的可以在你的例子中使用任何东西(Object
, Foo
,没关系)因为你永远无法添加任何东西null
,因为你直接将它分配给一个ArrayList<?>
引用。
回答by jon_darkstar
A lot of this has to do with polymorphism. When you assign
这在很大程度上与多态性有关。当你分配
X = new Y();
X can be much less 'specific' than Y, but not the other way around. X is just the handle you are accessing Y with, Y is the real instantiated thing,
X 可以比 Y 更不“具体”,但反过来不行。X 只是你用来访问 Y 的句柄,Y 是真正的实例化的东西,
You get an error here because Integer is a Number, but Number is not an Integer.
你在这里会得到一个错误,因为 Integer 是一个数字,但 Number 不是一个整数。
ArrayList<Integer> a = new ArrayList<Number>(); // compile-time error
As such, any method of X that you call must be valid for Y. Since X is more generally it probably shares some, but not all of Y's methods. Still, any arguments given must be valid for Y.
因此,您调用的 X 的任何方法都必须对 Y 有效。由于 X 更普遍,它可能共享一些但不是所有 Y 的方法。尽管如此,给出的任何参数都必须对 Y 有效。
In your examples with add, an int (small i) is not a valid Object or Integer.
在您添加的示例中,int(小 i)不是有效的对象或整数。
ArrayList<?> a = new ArrayList<?>();
This is no good because you can't actually instantiate an array list containing ?'s. You can declare one as such, and then damn near anything can follow in new ArrayList<Whatever>();
这不好,因为您实际上无法实例化包含 ? 的数组列表。你可以这样声明一个,然后该死的几乎任何东西都可以跟随new ArrayList<Whatever>();
回答by AlexR
ArrayList<Integer> a = new ArrayList<Number>();
Does not work because the fact that Number is a super class of Integer does not mean that List<Number>
is a super class of List<Integer>
. Generics are removed during compilation and do not exist on runtime, so parent-child relationship of collections cannot be be implemented: the information about element type is simply removed.
不起作用,因为 Number 是 Integer 的超类并不意味着它List<Number>
是List<Integer>
. 泛型在编译时被移除,在运行时不存在,因此无法实现集合的父子关系:关于元素类型的信息被简单地移除。
ArrayList<? extends Object> a1 = new ArrayList<Object>();
a1.add(3);
I cannot explain why it does not work. It is really strange but it is a fact. Really syntax <? extends Object>
is mostly used for return values of methods. Even in this example Object o = a1.get(0)
is valid.
我无法解释为什么它不起作用。这真的很奇怪,但这是事实。真正的语法<? extends Object>
主要用于方法的返回值。即使在这个例子中Object o = a1.get(0)
也是有效的。
ArrayList<?> a = new ArrayList<?>()
This does not work because you cannot instantiate list of unknown type...
这不起作用,因为您无法实例化未知类型的列表...
回答by meriton
You have strange expectations. If you gave the chain of arguments that led you to them, we might spot the flaw in them. As it is, I can only give a short primer on generics, hoping to touch on the points you might have misunderstood.
你有奇怪的期望。如果你给出引导你的论据链,我们可能会发现它们的缺陷。事实上,我只能对泛型做一个简短的入门,希望能触及您可能误解的要点。
ArrayList<? extends Object>
is an ArrayList whose type parameter is known to be Object
or a subtype thereof. (Yes, extends in type bounds has a meaning other than direct subclass). Since only reference types can be type parameters, this is actually equivalent to ArrayList<?>
.
ArrayList<? extends Object>
是一个 ArrayList,其类型参数是已知的Object
或其子类型。(是的,类型边界中的扩展具有除直接子类之外的其他含义)。由于只有引用类型可以是类型参数,因此这实际上等效于ArrayList<?>
.
That is, you can put an ArrayList<String>
into a variable declared with ArrayList<?>
. That's why a1.add(3)
is a compile time error. a1
's declared type permits a1
to be an ArrayList<String>
, to which no Integer
can be added.
也就是说,您可以将 anArrayList<String>
放入一个用 声明的变量中ArrayList<?>
。这就是a1.add(3)
编译时错误的原因。a1
的声明类型允许a1
是 an ArrayList<String>
,Integer
可以添加no 。
Clearly, an ArrayList<?>
is not very useful, as you can only insert null into it. That might be why the Java Spec forbidsit:
显然, anArrayList<?>
不是很有用,因为您只能将 null 插入其中。这可能就是 Java 规范禁止它的原因:
It is a compile-time error if any of the type arguments used in a class instance creation expression are wildcard type arguments
如果在类实例创建表达式中使用的任何类型参数是通配符类型参数,则会出现编译时错误
ArrayList<ArrayList<?>>
in contrast is a functional data type. You can add all kinds of ArrayLists into it, and retrieve them. And since ArrayList<?>
only containsbut is nota wildcard type, the above rule does not apply.
ArrayList<ArrayList<?>>
相反的是功能数据类型。您可以向其中添加各种 ArrayList,并检索它们。由于ArrayList<?>
仅包含但不是通配符类型,因此上述规则不适用。
回答by Bert F
The key lies in the differences between references and instances and what the reference can promise and what the instance can really do.
关键在于引用和实例之间的区别,以及引用可以承诺什么以及实例真正可以做什么。
ArrayList<A> a = new ArrayList<A>();
Here a
is a reference to an instance of a specific type - exactly an array list of A
s. More explicitly, a
is a reference to an array list that will accept A
s and will produce A
s. new ArrayList<A>()
is an instance of an array list of A
s, that is, an array list that will accept A
s and will produce A
s.
这a
是对特定类型实例的引用 - 正是A
s的数组列表。更明确地说,a
是对接受A
s 并产生A
s的数组列表的引用。 new ArrayList<A>()
是A
s的数组列表的实例,即接受A
s 并生成A
s的数组列表。
ArrayList<Integer> a = new ArrayList<Number>();
Here, a
is a reference to exactly an array list of Integers
, i.e. exactly an array list that can accept Integer
s and will produce Integer
s. It cannot point to an array list of Number
s. That array list of Number
s can not meet all the promises of ArrayList<Integer> a
(i.e. an array list of Number
s may produce objects that are not Integer
s, even though its empty right then).
这里,a
是对 的一个数组列表的引用Integers
,也就是一个可以接受Integer
s 并产生Integer
s的数组列表。它不能指向Number
s的数组列表。Number
s 的数组列表不能满足所有的承诺ArrayList<Integer> a
(即Number
s的数组列表可能产生不是Integer
s 的对象,即使它当时是空的)。
ArrayList<Number> a = new ArrayList<Integer>();
Here, declaration of a
says that a
will refer to exactly an array list of Number
s, that is, exactly an array list that will accept Number
s and will produce Number
s. It cannot point to an array list of Integer
s, because the type declaration of a
says that a
can accept any Number
, but that array list of Integer
s cannot accept just any Number
, it can only accept Integer
s.
在这里,声明a
表示a
将完全引用Number
s的数组列表,也就是说,恰好是一个将接受Number
s 并生成Number
s的数组列表。它不能指向Integer
s的数组列表,因为 的类型声明a
说a
可以接受 any Number
,但是Integer
s 的数组列表Number
不能只接受any ,它只能接受Integer
s。
ArrayList<? extends Object> a= new ArrayList<Object>();
Here a
is a (generic) reference to a family of typesrather than a reference to a specific type. It can point to any list that is member of that family. However, the trade-off for this nice flexible reference is that they cannot promise all of the functionality that it could if it were a type-specific reference (e.g. non-generic). In this case, a
is a reference to an array list that will produceObject
s. But, unlike a type-specific list reference, this a
reference cannot acceptany Object
. (i.e. not every member of the family of types that a
can point to can accept any Object
, e.g. an array list of Integer
s can only accept Integer
s.)
这a
是对一系列类型的(通用)引用,而不是对特定类型的引用。它可以指向属于该家族成员的任何列表。然而,这种灵活的引用的折衷是,如果它是特定于类型的引用(例如,非泛型引用),则它们不能保证它可以提供的所有功能。在这种情况下,a
是对将产生Object
s的数组列表的引用。但是,与特定于类型的列表引用不同,此a
引用不能接受任何Object
. (即,并非a
可以指向的类型家族的每个成员都可以接受 any Object
,例如Integer
s的数组列表只能接受Integer
s。)
ArrayList<? super Integer> a = new ArrayList<Number>();
Again, a
is a reference to a family of types (rather than a single specific type). Since the wildcard uses super
, this list reference can accept Integer
s, but it cannot produce Integer
s. Said another way, we know that any and every member of the family of types that a
can point to can accept an Integer
. However, not every member of that family can produce Integer
s.
同样,a
是对一系列类型(而不是单个特定类型)的引用。由于通配符使用super
,此列表引用可以接受Integer
s,但不能产生Integer
s。换句话说,我们知道a
可以指向的类型家族的任何成员都可以接受Integer
. 但是,并非该家庭的每个成员都能产生Integer
s。
PECS- Producer extends
, Consumer super
- This mnemonic helps you remember that using extends
means the generic type can producethe specific type (but cannot accept it). Using super
means the generic type can consume(accept) the specific type (but cannot produce it).
PECS- Producer extends
, Consumer super
- 这个助记符可以帮助您记住 using extends
表示泛型类型可以生成特定类型(但不能接受它)。使用super
意味着泛型类型可以使用(接受)特定类型(但不能产生它)。
ArrayList<ArrayList<?>> a
An array list that holds references to any list that is a member of a family of array lists types.
保存对属于数组列表类型家族成员的任何列表的引用的数组列表。
= new ArrayList<ArrayList<?>>(); // correct
An instance of an array list that holds references to any list that is a member of a family of array lists types.
数组列表的一个实例,它保存对属于数组列表类型系列成员的任何列表的引用。
ArrayList<?> a
An reference to any array list (a member of the family of array list types).
对任何数组列表(数组列表类型家族的成员)的引用。
= new ArrayList<?>()
ArrayList<?>
refers to any type from a family of array list types, but you can only instantiate a specific type.
ArrayList<?>
指的是数组列表类型系列中的任何类型,但您只能实例化特定类型。
See also How can I add to List<? extends Number> data structures?
回答by Dudus
Think of the ?
as to mean "unknown"
. Thus, "ArrayList<? extends Object>"
is to say "an unknown type that (or as long as it)extends Object". Therefore, needful to say, arrayList.add(3)
would be putting something you know, into an unknown. I.e 'Forgetting'.
将?
视为 的意思"unknown"
。因此,"ArrayList<? extends Object>"
就是说“(或只要它)扩展对象的未知类型”。因此,有必要说,arrayList.add(3)
将你知道的东西放入一个未知的东西中。即“忘记”。