代码<E>
有什么含义 Collection<E>
?
答案 0 :(得分:18)
这意味着您正在处理类型为E
的项目集合。想象一下,你喝了一杯茶。它也可以拿咖啡代替茶,因此将杯子描述为一个通用实体是有意义的:
class Cup<T> { … }
现在你可以用咖啡或茶(或其他东西)来填充它:
Cup<Tea> cuppa = new Cup<Tea>();
Cup<Coffee> foamee = new Cup<Coffee>();
为了实现这一点,Tea
和Coffee
都需要是程序中定义的类型。
这是您代码上的编译时约束。从(相当无用的)杯子示例回来,集合(数组,列表......)通常包含一个类型的项目,例如整数或字符串。泛型帮助您在Java中表达这一点:
Collection<String> strList = new ArrayList<String>();
strList.add("Foobar"); // Works.
strList.add(42); // Compile error!
注意上面的编译错误?你只有在使用泛型时才会得到这个。以下代码也有效,但不会给出错误消息:
Collection strList = new ArrayList();
strList.add("Foobar"); // Works.
strList.add(42); // Works now. Do we really want this?!
答案 1 :(得分:15)
这是泛型的使用。检查此intro。然后别忘了阅读tutorial。
摘录如下(比较演员与使用仿制品的比较):
当您看到代码&lt; Type&gt;时,请阅读它 作为“类型”;上面的声明 读作“字符串集合c。” 使用泛型的代码更清晰 更安全。我们已经消除了不安全因素 演员和一些额外的 括弧。更重要的是,我们有 移动了部分规范 从评论到其的方法 签名,所以编译器可以验证 在编译时该类型 在运行时不会违反约束 时间。因为程序编译 没有警告,我们可以陈述 确定它不会扔掉 运行时ClassCastException。该 使用泛型的净效应, 特别是在大型节目中,是 提高了可读性和稳健性。
例如,List的界面是
public interface List<E> {
void add(E x);
Iterator<E> iterator();
}
这意味着您可以构建一个列表,其内容都是相同的显式类型(不仅是Object类型),即使您自己定义了类型。因此,如果您创建一个Name类,则可以编写
List<Name> nameList = new ArrayList<>();
然后用Name实例填充它并直接从中检索Name实例,而不必抛出或担心它,因为你总是得到一个Name实例或null返回,而不是一个不同类型的实例。
更重要的是,你不能在这样的List中插入与Name实例不同的东西,因为它会在编译时失败。
nameList.add(false); //Fails!
nameList.add(new Name("John","Smith")); //Succeeds supposing Name has a
//firstName, lastName constructor