当前位置:  开发笔记 > 编程语言 > 正文

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

如何解决《JavaGenerics:List,List<Object>,List<?>》经验,为你挑选了4个好方法。

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

List
List
List


让我更具体一点.我什么时候想用

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

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

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

jjohn.. 102

正如其他帖子所指出的那样,您要问的是一个名为泛型的Java功能.在C++中,这称为模板.Java野兽的处理方式更加温和.

让我在功能上回答你的问题(如果这不是OO讨论的顽皮词).

在泛型之前,你有像Vector这样的旧混凝土类.

Vector V = new Vector();

向量包含您给它们的任何旧对象.

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

但是,他们通过将您提供的所有内容都转换为Object(所有Java类的根目录)来实现此目的.在您尝试检索存储在Vector中的值之前,这没关系.当你这样做时,你需要将值转换回原始类(如果你想用它做任何有意义的事情).

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

铸造变得非常快.更重要的是,编译器向你抱怨未经检查的强制转换.有关这方面的生动示例,请使用Apache的XML-RPC库(无论如何都是版本2).最重要的问题是,Vector的使用者必须在编译时知道其值的确切类,才能正确转换.如果Vector的生产者和消费者彼此完全隔离,这可能是一个致命的问题.

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

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

现在,如果你看看臭名昭着的四人组合设计模式书,你会注意到从他们的实现类中脱离变量有一些智慧.考虑合同而不是实施更好.所以,你可能会说,所有清单对象做同样的事情:add(),get(),size()等.然而,也有列表的操作是可以选择服从以各种方式(如合同的许多实现ArrayList).但是,这些对象处理的数据类型将作为运行时考虑因素留给您(泛型类的用户).把它们放在一起,你会经常看到以下代码行:

List L = new ArrayList();

您应该读作"L是一种处理String对象的List".当您开始处理Factory类时,处理合同而不是特定的实现是至关重要的.工厂在运行时生成各种类型的对象.

使用泛型很容易(大多数时候).但是,有一天你可能决定要实现泛型类.也许您已经想到了一个很棒的新List实现.定义该类时,可以将其用作将由方法操作的对象类型的占位符.如果您感到困惑,请使用List的通用类,直到您感到舒服为止.然后,您可以更自信地深入了解实施.或者,您可以查看JRE附带的各种List类的源代码.开源很棒.

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



1> jjohn..:

正如其他帖子所指出的那样,您要问的是一个名为泛型的Java功能.在C++中,这称为模板.Java野兽的处理方式更加温和.

让我在功能上回答你的问题(如果这不是OO讨论的顽皮词).

在泛型之前,你有像Vector这样的旧混凝土类.

Vector V = new Vector();

向量包含您给它们的任何旧对象.

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

但是,他们通过将您提供的所有内容都转换为Object(所有Java类的根目录)来实现此目的.在您尝试检索存储在Vector中的值之前,这没关系.当你这样做时,你需要将值转换回原始类(如果你想用它做任何有意义的事情).

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

铸造变得非常快.更重要的是,编译器向你抱怨未经检查的强制转换.有关这方面的生动示例,请使用Apache的XML-RPC库(无论如何都是版本2).最重要的问题是,Vector的使用者必须在编译时知道其值的确切类,才能正确转换.如果Vector的生产者和消费者彼此完全隔离,这可能是一个致命的问题.

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

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

现在,如果你看看臭名昭着的四人组合设计模式书,你会注意到从他们的实现类中脱离变量有一些智慧.考虑合同而不是实施更好.所以,你可能会说,所有清单对象做同样的事情:add(),get(),size()等.然而,也有列表的操作是可以选择服从以各种方式(如合同的许多实现ArrayList).但是,这些对象处理的数据类型将作为运行时考虑因素留给您(泛型类的用户).把它们放在一起,你会经常看到以下代码行:

List L = new ArrayList();

您应该读作"L是一种处理String对象的List".当您开始处理Factory类时,处理合同而不是特定的实现是至关重要的.工厂在运行时生成各种类型的对象.

使用泛型很容易(大多数时候).但是,有一天你可能决定要实现泛型类.也许您已经想到了一个很棒的新List实现.定义该类时,可以将其用作将由方法操作的对象类型的占位符.如果您感到困惑,请使用List的通用类,直到您感到舒服为止.然后,您可以更自信地深入了解实施.或者,您可以查看JRE附带的各种List类的源代码.开源很棒.

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


登录只是+1这个优秀的答案 - 简洁明了!
不讨论<?>的使用

2> OscarRyz..:

用我自己的简单术语:

名单

将声明一个普通的集合,可以保存任何类型,并将始终返回Object.

列表<对象>

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

例如,这不起作用;

List l = new ArrayList();


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

List l = new ArrayList();

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

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


最后

名单<?>

会让你指定任何类型,包括

List  l = new ArrayList(); 
List  l2 = new ArrayList();

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

当它与子类化一起使用时,未知的重要性来自:

List l = new ArrayList(); // compiles

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

我希望使用Collection作为类型不会产生混淆,这是我想到的唯一一棵树.

这里的不同之处在于l是属于Collection层次结构的unknow 集合.



3> Rob..:

我将向您介绍优秀的Java Generics教程,以及Sun Microsystems提供的"高级"泛型教程.另一个很好的资源是Java Generics and Collections一书.


我认为社区将决定回答这个问题的最佳方式.
可能他认为这是为了你自己的利益.:-)
有时人们希望以不同的方式听到它的解释.
好的,但是我的问题是,我只想要一个快速而肮脏的答案,不要对你的链接如此敏感.
全部说明:由于ForYourOwnGood和Rob之间的这种分歧,Rob在ForYourOwnGood的答案中获得了7分,所以如果你在任何问题上不同意Rob,那么请准备好失去一些分数.
最终,虽然您可能已经提出了问题,但该网站的目标是使该问题成为未来访问者的更通用的参考资源.我发布了两个教程的链接,因为它们全面地解释了一个相当复杂的主题.

4> Eric Lindaue..:

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

方法参数:

List

如果您不打算更改列表,那么这是一个很好的选择,只关心列表中的所有内容都可以分配给'Foo'.这样,调用者可以传入List 并且您的方法可以正常工作.通常是最好的选择.

List

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

List

如果你打算将Foo对象添加到列表中,这是一个很好的选择,并且列表中的其他内容并不重要(例如,您可以获得包含与Foo无关的'Dog'的List ).

方法返回值

就像方法论证一样,但好处却逆转了.

List

保证返回List中的所有内容都有'Foo'类型.它可能是List .来电者无法添加到列表中.这是您的首选,也是迄今为止最常见的案例.

List

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

List

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

我希望有所帮助.祝好运!

PS.总结......两个问题......

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

是是 - 使用List .

是否 - 使用清单<?超级富豪>.

不是 - 使用<?扩展Foo> ---最常见.

不能 - 使用<?>.

推荐阅读
yzh148448
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有