为了账号安全,请及时绑定邮箱和手机立即绑定

请问Java泛型:列表,列表<对象>,列表<?>

/ 猿问

请问Java泛型:列表,列表<对象>,列表<?>

海绵宝宝撒 2019-10-21 16:12:08

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

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


List

List<Object>

List<?>

让我说得更具体些。我什么时候想用


// 1 

public void CanYouGiveMeAnAnswer(List l) { }


// 2

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


// 3

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


查看完整描述

3 回答

?
慕莱坞森

正如其他帖子所指出的,您询问的是一个名为泛型的Java特性。在C+中,这称为模板。Java的行为是很难处理的。

让我从功能上回答你的问题(如果这不是OO讨论的调皮词)。

在泛型之前,您有像Vectore这样的好的旧具体类。

Vector V = new Vector();

向量保存着你给他们的任何旧的物体。

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

但是,它们通过将您提供给它的所有内容转换为一个对象(所有Java类的根)来实现这一点。这是可以的,直到您尝试检索存储在您的向量中的值。当您这样做时,您需要将该值转换回原始类(如果您想对它执行任何有意义的操作)。

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

演员很快就会变老。不仅如此,编译器还向您抱怨未经检查的强制转换。关于这方面的生动示例,请使用Apache中的XML-RPC库(至少第2版)。这方面最重要的问题是,您的向量的使用者必须知道其值的确切类别编译时间才能正确的投出。在病媒生产者和消费者完全相互隔离的情况下,这可能是一个致命的问题。

输入仿制药。泛型试图创建强类型类来执行泛型操作。

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

现在,如果你看看臭名昭著的四人帮设计模式在书中,您会注意到将变量与其实现类分离是一种明智的做法。与其考虑执行,不如考虑合同。因此,您可能会说,所有List对象都执行相同的操作:add()get()size()然而,有许多列表操作的实现可以选择以各种方式遵守合同。ArrayList)。但是,这些对象处理的数据类型作为运行时的考虑因素留给了泛型类的用户。将所有这些放在一起,您将非常频繁地看到以下代码行:

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

你应该把它读成“L是一种处理字符串对象的列表”。当您开始处理Factory类时,处理契约而不是特定的实现是至关重要的。工厂在运行时生成各种类型的对象。

使用泛型相当容易(大多数情况下)。但是,有一天,您可能会决定要实现一个泛型类。也许您已经想到了一个很棒的新列表实现。定义该类时,可以使用<t>作为将被方法操作的对象类型的占位符。如果您感到困惑,请使用泛型类作为列表,直到您感到满意为止。然后,您可以更加自信地投入到实现中。或者您可以查看JRE附带的各种列表类的源代码。开放源码是很好的方式。

看看Oracle/Sun关于泛型的文档..干杯。



查看完整回答
反对 回复 2019-10-22
?
白衣非少年

用我自己简单的话说:


列单


将声明一个普通集合,可以保存任何类型,并将始终返回对象。


列表<Object>


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


例如,这是行不通的;


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

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


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


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<String>();

这将被称为未知数既然共同的分母未知数是您将能够获取对象的对象(巧合)。


.的重要性未知数当它与子类一起使用时:


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. 

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


这里的区别是,我是不知道属于收藏等级制度。



查看完整回答
反对 回复 2019-10-22
?
慕沐林林

为了在这里补充已经很好的答案:

方法论据:

List<? extends Foo>

如果您不打算更改列表,并且只关心列表中的所有内容都可指定为“foo”,则是一个不错的选择。这样,调用方就可以传递一个列表<foosubclass>,并且您的方法可以工作。通常是最好的选择。

List<Foo>

如果您打算将foo对象添加到您的方法中的列表中,这是很好的选择。调用方可能不会传入列表<foosubclass>,因为您打算向列表中添加foo。

List<? super Foo>

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

方法返回值

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

List<? extends Foo>

确保返回列表中的所有内容都键入“foo”。不过,它可能是List<foosubclass>。调用方不能添加到列表中。这是你的选择,也是目前为止最常见的情况。

List<Foo>

就像列表<?扩展foo>,但也允许调用方将其添加到列表中。不那么普通。

List<? super Foo>

允许调用方将foo对象添加到列表中,但不能保证从list.get(0).它可能是从Foo到Object的任何东西。唯一的保证是,这不会是一个列表的‘狗’或其他一些选择,以防止list.add(Foo)是合法的。非常罕见的用例。

我希望这能帮上忙。祝好运!

PS。总之.。两个问题.。

您需要添加到列表中吗?你在乎名单上有什么吗?

是的-使用列表<foo>。

是的,不使用列表<?超级福>

不,是的-使用<?扩展foo>-最常见的。

不使用<?>



查看完整回答
反对 回复 2019-10-22

添加回答

回复

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信