4

为什么我可以有一个方法接收带有通配符的列表:

public processGenerics(List<? extends User> users){...}

但我不能以类似的方式实例化同一个列表?

List<? extends User> alist = new ArrayList<? extends User>();

[已编辑,不是原始问题的一部分,但相关] 为什么我不能以与正常继承相同的方式对 Collections 进行强制转换:

List<User> users = new ArrayList<Admin>();
4

4 回答 4

4

问题中最令人困惑的方面是泛型类型与经典原始类型之间必须经历的潜在心理转换。

在泛型之前,每个变量都有一个明确的类型,例如 Object。尽管您可以将一个字符串分配给它,但一个字符串仍然是一个对象,因此范式成立——在所有情况下,您都将一个对象分配给一个 Object var。

泛型并非如此。您可能有一个List<? extends Number>,它可以从与声明的变量类型无关的一系列类型中分配instanceof,但只满足某种模式。模式由通配符描述。

因此,为了让您在推理泛型变量类型时更轻松,您需要放弃明确类型的简单而舒适的概念,并根据这些“类型模式”进行思考。

至于你问题的第二部分:List<User>and是完全不相关的类型,不管and是相关List<Admin>的事实。这就是泛型的工作方式,这是有充分理由的。Java 不允许您添加到, 并且根据您的假设可能会发生:UserAdminOrdinaryUserList<Admin>

List<User> users = new ArrayList<Admin>();
users.add(new OrdinaryUser()); // shouldn't be allowed!

官方术语是泛型类型在其类型参数方面是不变的。最好用谷歌搜索这个术语,因为它已经很好地涵盖了。

于 2012-09-28T11:23:17.253 回答
4

构造:

List<? extends User> user

表示可以保存 的实例的变量List<T>,其中T是用户的某个未知子类型。当你实际实例化 anArrayList<T>时,你总是知道它应该持有什么类型,所以让你在那里表达这种不确定性是没有用的。

换一种说法:一个变量可以保存(可能)许多不同类型的对象。一个对象实例只有它自己的一种类型。这就是为什么变量声明必须更加灵活的原因。

于 2012-09-28T11:13:56.533 回答
3

您不能实例化通配符实例。您只能实例化一个特定的实例,例如:

List<? extends User> alist1 = new ArrayList<User>();
List<? extends User> alist2 = new ArrayList<SubClassOfUser>();

什么List<? extends User>意思是“一个列表,其类型在编译时未知,但它的上限是User-或者是”User的子类User

虽然可以使用通配符定义变量 ,但实例可能不会 - 它必须是某物的列表

于 2012-09-28T11:12:49.830 回答
-1

new 运算符通过为新对象分配内存并返回对该内存的引用来实例化一个类。甲骨文

当您使用通配符创建对象时,您无法知道要分配多少内存。

作为参数类型传递给方法的内容不涉及内存分配。

于 2012-09-28T11:47:31.803 回答