Java 泛型:列表、列表<对象>、列表<?>

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/490091/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:18:12  来源:igfitidea点击:

Java Generics: List, List<Object>, List<?>

javagenerics

提问by ForYourOwnGood

Can someone explained, as detailed as possible, the differences between the following types?

有人可以尽可能详细地解释以下类型之间的区别吗?

List
List<Object>
List<?>

Let me make this more specific. When would I want to use

让我更具体地说明这一点。我什么时候想用

// 1 
public void CanYouGiveMeAnAnswer(List l) { }

// 2
public void CanYouGiveMeAnAnswer(List<Object> l) { }

// 3
public void CanYouGiveMeAnAnswer(List<?> l) { }

回答by Rob

I refer you to the excellent Java Generics tutorial, and the "advanced" Generics tutorial, both available from Sun Microsystems. Another great resource is the Java Generics and Collectionsbook.

我向您推荐优秀的Java 泛型教程“高级”泛型教程,两者都可以从 Sun Microsystems 获得。另一个很棒的资源是Java 泛型和集合这本书。

回答by Tim

To complement the tutorials mentioned by Rob, here's a wikibook explaining the topic:
http://en.wikibooks.org/wiki/Java_Programming/Generics

为了补充 Rob 提到的教程,这里有一本解释该主题的 wikibook:http:
//en.wikibooks.org/wiki/Java_Programming/Generics



Edit:

编辑:

  1. No restrictions on type of items in list

  2. Items in list must extend Object

  3. Wildcard used by itself, so it matches anything

  1. 对列表中的项目类型没有限制

  2. 列表中的项目必须扩展对象

  3. 通配符本身使用,所以它匹配任何东西

Would it be naive of me to conclude at this point that there's hardly any/no difference at all?

在这一点上得出几乎没有任何区别/根本没有区别的结论是否太天真了?

回答by John Gardner

Simplest explanation which is not "RTFM":

不是“RTFM”的最简单的解释:

List

Will generate lots of compiler warnings, but is mostly equivalent to:

会产生很多编译器警告,但大部分等同于:

List<Object>

While:

尽管:

List<?>

basically means its something generic, but you don't know what the generic type is. Its great for getting rid of compiler warnings when you cant modify the return types of other things that just returned List. Its much more useful in the form:

基本上意味着它是通用的,但你不知道通用类型是什么。当您无法修改刚刚返回 List 的其他事物的返回类型时,它非常适合摆脱编译器警告。它的形式更有用:

List<? extends SomeOtherThing>

回答by Eddie

The shortest possible explanation is: The second item is a list that can hold any type, and you can add objects to it:

最简短的解释是:第二项是一个可以容纳任何类型的列表,您可以向其中添加对象:

List<Object>

The first item you list is treated as essentially equivalent to this, except you will get compiler warnings because it is a "raw type".

您列出的第一项被视为与此基本等效,除非您将收到编译器警告,因为它是“原始类型”。

List

The third is a list that can hold any type, but you cannot add anything to it:

第三个是可以容纳任何类型的列表,但不能向其中添加任何内容:

List<?> 

Basically, you use the second form (List<Object>) when you truly have a list that can contain any object and you want to be able to add elements to the list. You use the third form (List<?>)when you receive the list as a method return value and you will iterate over the list but never add anything to it Never use the first form (List) in new code compiling under Java 5 or later.

基本上,List<Object>当您真正拥有一个可以包含任何对象的列表并且您希望能够向列表中添加元素时,您可以使用第二种形式 ( )。List<?>当您收到作为方法返回值的列表时,您使用第三种形式 ( ) 并且您将遍历该列表但从不向其中添加任何内容 不要List在 Java 5 或更高版本下编译的新代码中使用第一种形式 ( )。

回答by Fabian Steeg

I'd put it this way: While Listand List<Object>can contain any type of objects, List<?>contains elements of an unknown type, but once that type is captured, it can only contain elements of that type. Which is why it is the only type safe variant of those three, and therefore generally preferable.

我会这样说:虽然ListList<Object>可以包含任何类型的对象,List<?>包含未知类型的元素,但是一旦捕获了该类型,它就只能包含该类型的元素。这就是为什么它是这三个变体中唯一的类型安全变体,因此通常更可取。

回答by OscarRyz

In my own simple terms:

用我自己的简单来说:

List

列表

Would declare an ordinary collection, can hold any type, and will always return Object.

将声明一个普通集合,可以容纳任何类型,并且将始终返回 Object。

List<Object>

列表<对象>

Will create a list that can hold any type of object, but can only get assigned a another List<Object>

将创建一个可以容纳任何类型对象的列表,但只能分配一个另一个List<Object>

For instance this doesn't work;

例如,这不起作用;

List<Object> l = new ArrayList<String>();

Of course you can add anything but only can pull Object.

当然你可以添加任何东西,但只能拉出对象。

List<Object> l = new ArrayList<Object>();

l.add( new Employee() );
l.add( new String() );

Object o = l.get( 0 );
Object o2 = l.get( 1 );

Finally

最后

List<?>

列表<?>

Will let you assign any type, including

会让你分配任何类型,包括

List <?> l = new ArrayList(); 
List <?> l2 = new ArrayList<String>();

This would be called collection of unknownand since the common denominator of unknownis Object you will be able to fetch Objects ( a coincidence )

这被称为收集未知以来的共同点未知的对象,你就能获取对象(巧合)

The importance of unknowncomes when its used with subclassing:

当与子类化一起使用时,unknown的重要性就来了:

List<? extends Collection> l = new ArrayList<TreeSet>(); // compiles

List<? extends Collection> l = new ArrayList<String>(); // doesn't,
// because String is not part of *Collection* inheritance tree. 

I hope using Collection as the type doesn't create confusion, that was the only tree that came to my mind.

我希望使用 Collection 作为类型不会造成混乱,这是我想到的唯一树。

The difference here, is that l is a collection of unknowthat belongs to the Collectionhierarchy.

这里的区别在于, l 是属于Collection层次结构的未知集合

回答by OscarRyz

When would I want to use

我什么时候想用

public void CanYouGiveMeAnAnswer( List l ){}

When you cant to do all the casting your self.

当你不能做所有的铸造你自己。

When would I want to use

我什么时候想用

public void CanYouGiveMeAnAnswer( List l<Object> ){}

When you want to restrict the type of the List. For instance, this would be an invalid argument.

当您想限制 List 的类型时。例如,这将是一个无效的参数。

 new ArrayList<String>();

When would I want to use

我什么时候想用

public void CanYouGiveMeAnAnswer( List l<?> ){}

Mostly never.

主要是从来没有。

回答by jjohn

As the other posts have noted, you are asking about a Java feature called generics. In C++, this is called templates. This feature in Java is usually easier to work with than the that found in C++.

正如其他帖子所指出的,您是在询问称为泛型的 Java 功能。在 C++ 中,这称为模板。Java 中的此功能通常比 C++ 中的功能更易于使用。

Let me answer your questions functionally (if that's not a naughty word for OO discussions).

让我从功能上回答您的问题(如果这对 OO 讨论来说不是一个顽皮的话)。

Before generics, there were concrete classes like Vector.

在泛型之前,有像 Vector 这样的具体类。

Vector V = new Vector();

Vectors hold any object you give them.

向量包含您提供给它们的任何对象。

V.add("This is an element");
V.add(new Integer(2));
v.add(new Hashtable());

They do this by casting all values given to it into an Object (the root of all Java classes). When you attempt to retrieve the values stored in your Vector, you need to cast the value back into the originalclass (if you want to do anything meaningful with it).

他们通过将所有赋予它的值转换为一个对象(所有 Java 类的根)来实现这一点。当您尝试检索存储在 Vector 中的值时,您需要将该值转换回原始类(如果您想对其进行任何有意义的操作)。

String s = (String) v.get(0);
Integer i = (Integer) v.get(1);
Hashtable h = (Hashtable) v.get(2);

Casting gets old fast. More than that, the compiler complains to you about unchecked casts. The most urgent problem with casting like this is that consumers of your Vector have to know the classes of its values at compile timein order to cast correctly. In cases where the producer of the Vector and the consumer of the same are completely isolated from each other (think RPC messages), this can be a fatal issue.

铸造会很快变老。不仅如此,编译器还会向您抱怨未经检查的强制转换。像这样的转换最紧迫的问题是 Vector 的使用者必须在编译时知道其值的类才能正确转换。在 Vector 的生产者和消费者完全相互隔离的情况下(想想 RPC 消息),这可能是一个致命的问题。

Enter generics. Generics attempt to create strongly typed classes to do generic operations.

输入泛型。泛型尝试创建强类型类来执行泛型操作。

ArrayList<String> aList = new ArrayList<String>();
aList.add("One");
String element = aList.get(0); // no cast needed
System.out.println("Got one: " + element); 

The Design Patternsbook encourages the reader to think in terms of contracts, not concrete types. There is wisdom (and code re-use) in divorcing variables from their implementing class.

设计模式》一书鼓励读者根据契约而非具体类型进行思考。从实现类中分离变量是明智的(和代码重用)。

With this in mind, you might think that all implementations List objects should do the same set of things: add(), get(), size(), etc. With a little reflection, you can imagine many implementations of List operations that obey the List contract in various ways (e.g. ArrayList). However, the type of data these objects deal with is orthogonal to the actions performed on them.

考虑到这一点,你可能会认为,所有实现List对象应该做同样的一套东西:add()get()size()等有了一点点反思,你可以想像列表操作的许多实现服从以各种方式列表合同(例如ArrayList) . 但是,这些对象处理的数据类型与对它们执行的操作是正交的。

Put it all together and you'll see the following kinds of code frequently:

把它们放在一起,你会经常看到以下类型的代码:

List<String> L = new ArrayList<String>();

You should read that as "L is a kind of List that deals with String objects". When you start dealing with Factory classes, it is critical to deal with contracts rather than specific implementations. Factories produce objects of various types at runtime.

您应该将其读作“L 是一种处理字符串对象的列表”。当您开始处理工厂类时,处理契约而不是具体的实现是至关重要的。工厂在运行时生产各种类型的对象。

Using generics is pretty easy (most of the time).

使用泛型非常简单(大多数时候)。

One day you may decide you want to implement your own generic class. Perhaps you want to write a new database abstraction interface that elides the differencesbetween various data stores. When you define that generic class, you will use <t>as a placeholder for the kind of object that will be manipulated by the methods.

有一天,您可能决定要实现自己的泛型类。也许您想编写一个新的数据库抽象接口来消除各种数据存储之间的差异。当您定义该泛型类时,您将<t>用作将由方法操作的对象类型的占位符。

If you are still confused, use the generic classes for List until you are comfortable. Later, you can dive into the implementation with a bit more confidence. Or you can look at the source code for the various List classes that ship with the JRE. Open source is great that way.

如果您仍然感到困惑,请使用 List 的泛型类,直到您感到满意为止。稍后,您可以更加自信地深入研究实现。或者,您可以查看 JRE 附带的各种 List 类的源代码。开源在这方面很棒。

Have a look at the Oracle/Sun docs about generics. Cheers.

查看有关泛型的 Oracle/Sun文档。干杯。

回答by Eric Lindauer

To add to the already good answers here:

在这里添加已经很好的答案:

Method arguments:

方法参数:

List<? extends Foo>

List<? extends Foo>

good choice if you don't intend to alter the list, and only care that everything in the list is assignable to type 'Foo'. This way, the caller can pass in a List<FooSubclass> and your method works. Usually the best choice.

如果您不打算更改列表,并且只关心列表中的所有内容都可以分配到类型“Foo”,那么这是一个不错的选择。这样,调用者可以传入 List<FooSubclass> 并且您的方法可以工作。通常是最好的选择。

List<Foo>

List<Foo>

good choice if you intend to add Foo objects to the list in your method. The caller may not pass in a List<FooSubclass>, as you intend to add a Foo to the List.

如果您打算将 Foo 对象添加到您的方法中的列表中,这是一个不错的选择。调用者可能不会传入 List<FooSubclass>,因为您打算将 Foo 添加到 List。

List<? super Foo>

List<? super Foo>

good choice if you intend to add Foo objects to the list, and it's not important what else is in the list (ie, you are ok getting a List<Object> that contains a 'Dog' that has nothing to do with Foo).

如果您打算将 Foo 对象添加到列表中,这是一个不错的选择,并且列表中的其他内容并不重要(即,您可以获取包含与 Foo 无关的“Dog”的 List<Object> )。

Method return values

方法返回值

just like method arguments, but with the benefits reversed.

就像方法参数一样,但好处相反。

List<? extends Foo>

List<? extends Foo>

Guarantees that everything in the returned List has type 'Foo'. It might be List<FooSubclass> though. Caller cannot add to the List. This is your go-to choice and the most common case by far.

保证返回的 List 中的所有内容都具有“Foo”类型。不过它可能是 List<FooSubclass> 。来电者无法添加到列表中。这是您的首选,也是迄今为止最常见的情况。

List<Foo>

List<Foo>

Just like List<? extends Foo> but also allows the caller to add to the List. Less common.

就像 List<? 扩展 Foo> 但也允许调用者添加到列表中。不常见。

List<? super Foo>

List<? super Foo>

allows the caller to add Foo objects to the List, but does not guarantee what will be returned from list.get(0)... it could be anything from Foo to Object. The only guarantee is that this won't be a list of 'Dog' or some other choice that would prevent list.add(foo) from being legal. Very rare use case.

允许调用者将 Foo 对象添加到 List,但不保证将从 list.get(0) 返回什么......它可以是从 Foo 到 Object 的任何东西。唯一的保证是这不会是一个 'Dog' 列表或其他一些会阻止 list.add(foo) 合法的选择。非常罕见的用例。

I hope that helps. Good luck!

我希望这有帮助。祝你好运!

ps. To sum up... two questions...

附:总结一下……两个问题……

do you need to add to the List? Do you care what is in the list?

yes yes - use List<Foo>.

yes no - use List<? super Foo>.

no yes - use <? extends Foo> --- most common.

no no - use <?>.

您需要添加到列表中吗?你关心列表中的内容吗?

是 是 - 使用 List<Foo>。

是 否 - 使用 List<? 超级Foo>。

否 是 - 使用 <? 扩展 Foo> --- 最常见。

不不 - 使用 <?>。

回答by PaulMurrayCbr

List, List<?>, and List<? extends Object>are the same thing. The second is more explicit. For a list of this type, you cannot know what types are legal to put into it, and you don't know anything about the types you can get out of it, except that they will be objects.

List, List<?>, and List<? extends Object>是一样的。第二个更明确。对于这种类型的列表,您无法知道将哪些类型放入其中是合法的,并且您对可以从中获取的类型一无所知,除了它们将是对象。

List<Object>specifically means that the list contains any sort of object.

List<Object>具体意味着该列表包含任何类型的对象。

Let's say we make a list of Foo:

假设我们列出了Foo

List<Foo> foos= new ArrayList<Foo>();

It is not legal to put a Barinto foos.

将 aBar放入 foos是不合法的。

foos.add(new Bar()); // NOT OK!

It is always legal to put anything into a List<Object>.

将任何内容放入List<Object>.

List<Object> objs = new ArrayList<Object>();
objs.add(new Foo());
objs.add(new Bar());

But you mustn't be allowed to put a Barinto a List<Foo>- that's the whole point. So that means that this:

但是您不能被允许将 aBar放入 a List<Foo>- 这就是重点。所以这意味着:

List<Object> objs = foos; // NOT OK!

is not legal.

不合法。

But it's ok to say that foos is a list of something but we don't know specifically what it is:

但是可以说 foos 是一个列表,但我们不知道它具体是什么:

List<?> dontKnows = foos;

But that then means that it must be prohibited to go

但这意味着必须禁止去

dontKnows.add(new Foo()); // NOT OK
dontKnows.add(new Bar()); // NOT OK

because the variable dontKnows does't know what types are legal.

因为变量 dontKnows 不知道哪些类型是合法的。