无界通配符类型List 和原始类型List之间有什么区别?
你能帮我理解无界通配符类型列表和原始类型列表之间的区别吗?
List b; // unbounded wildcard type List a; // raw type
除此之外,任何人都可以帮助我理解什么是有界类型参数列表 ?
List c;
以下是三者的总结:
-
List
:没有类型参数的列表。 它是一个列表,其元素是任何类型 – 元素可以是不同类型 。 -
List>
:具有无界类型参数的列表。 它的元素是一种特定但未知的类型; 元素必须都是相同的类型 。 -
List
:一个名为T
的类型参数的列表。T
提供的类型必须是扩展E
的类型,或者它不是参数的有效类型。
你应该看看Effective Java,第23项:不要在新代码中使用原始类型。
要使用该书中的示例,请考虑以下示例…如果您有一个不关心其中包含哪些类型元素的集合,该怎么办? 例如,您想要查看两个集合之间共有多少个元素。 您可能会想出以下内容:
public static int numElementsInCommon(Set s1, Set s2) { int result = 0; for (Object o : s1) { if (s2.contains(o)) { ++result; } } return result; }
这个例子虽然有效,但由于使用了原始类型,因此不是一个好主意。 原始类型根本不是类型安全的……你最终可能会以一种非类型安全的方式修改集合并破坏你的程序。 相反,谨慎一点并使用类型安全的替代方案:
public static int numElementsInCommon(Set> s1, Set> s2) { int result = 0; for (Object o : s1) { if (s2.contains(o)) { ++result; } } return result; }
区别在于您只能向Set>
添加null
,并且您不能假设您从Set>
取出的元素。 如果您使用原始Set
,则可以添加任何您想要的内容。 numElementsInCommon
方法是一个很好的示例,您甚至不需要添加任何内容,也不需要假设集合中的内容。 这就是为什么它是一个很好的候选人使用?
通配符。
希望这可以帮助。 阅读有效Java中的整个项目,它将变得清晰。
要回答你问题的第二部分……记得我说你?
时候使用?
通配符,你不能假设你从集合中取出的元素? 如果您确实需要对从集合中删除的对象的接口做出假设,该怎么办? 例如,假设您想要跟踪一组Cool
事。
public interface Cool { // Reports why the object is cool void cool(); }
然后你可能会有这样的代码:
public static void reportCoolness(Set s) { for (Object item : s) { Cool coolItem = (Cool) item; coolItem.cool(); } }
这不是类型安全的……你需要确保传入一个只有Cool
对象的集合。 要解决它,你可能会说:
public static void reportCoolness(Set s) { for (Cool coolItem : s) { coolItem.cool(); } }
这很棒! 完全符合您的要求并且类型安全。 但是,如果以后你有这个:
public interface ReallyCool extends Cool { // Reports why the object is beyond cool void reallyCool(); }
由于所有ReallyCool
对象都Cool
,您应该能够执行以下操作:
Set s = new HashSet (); // populate s reportCoolness(s);
但是你不能这样做,因为generics具有以下属性:假设B
是A
的子类,则Set
不是Set
的子类。 对此的技术讨论是“通用类型是不变的”。 (与协变相反)。
要使最后一个示例起作用,您需要通过(安全地)转换Set
中的每个元素来创建Set
Set
。 为了避免让你的api的客户经历这个讨厌的,不必要的代码,你可以使reportCoolness
方法更灵活,如下所示:
public static void reportCoolness(Set extends Cool> s) { for (Cool coolItem : s) { coolItem.cool(); } }
现在你的方法采用包含Cool
元素或Cool
任何子类的任何Set
。 所有这些类型都遵循Cool
api …因此我们可以安全地对任何元素调用cool()
方法
合理? 希望这可以帮助。
在第一个问题上, List
和List>
之间的区别:
两者之间的一个显着区别是,当您使用通配符作为类型时, Collection
的类型是未知的,因此add
方法将引发编译时错误。
你仍然可以从List>
获取值,但是你需要一个显式的强制转换。