我看到的大多数代码总是按接口类型(例如Set)而不是按实现类型引用Collection。
以下是Oracle的Java教程提供的原因
这是一个强烈建议的编程实践,因为它可以仅通过更改构造函数来更改实现的灵活性。如果用于存储集合的变量或使用的参数传递它的声明为Collection的实现类型所有此类变量和参数都必须是更改以更改其实现类型。
此外,作者还表示,不能保证生成的程序会起作用。如果程序使用原始实现类型中存在的任何标准操作,但不在新的中,则程序将失败。仅通过集合的接口引用集合可以防止使用任何非标准操作。
作者谈到的不规范操作有哪些?
其次,为什么仅通过集合的接口来引用集合会阻止我们使用任何非标准操作?
请借助Java代码详细说明?
一个例子是LinkedList
,它有一个getFirst()
和getLast()
方法。使用它们似乎很方便,但如果实现更改为ArrayList
,它们就会消失。
使用接口for和instance初始化有多种优点。
List list = new Arraylist();
现在您有了list对象,它以后对实现list接口的任何类都有用。
但一旦你有了ArrayList arraylist = new ArrayList()
,你就会失去这样的机会。
即使在使用接口时,也需要考虑一个陷阱。
考虑以下代码:
public void sampleMethod(List<String> list) {
list.add("baz");
System.out.println(list);
}
我们只使用接口定义的标准操作,但如果您查看文档,您会注意到add()
操作是可选的。
因此,如果您执行以下代码
public void test() {
List<String> sampleList = new ArrayList<>();
sampleList.add("foo");
try {
sampleMethod(sampleList);
}catch (Exception e) {
e.printStackTrace();
}
try {
sampleMethod(Collections.unmodifiableList(sampleList));
}catch (Exception e) {
e.printStackTrace();
}
try {
sampleMethod(Collections.singletonList("bar"));
}catch (Exception e) {
e.printStackTrace();
}
}
你会得到:
[foo, baz]
java.lang.UnsupportedOperationException
at java.util.Collections$UnmodifiableCollection.add(Collections.java:1075)
...
java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
...
这就是为什么即使只使用standart操作,程序也会失败的一个例子。