为什么要首选Java类的接口?

时间:2008-09-29 04:02:56

标签: java collections interface

PMD会报告违规行为:

ArrayList<Object> list = new ArrayList<Object>();

违规是“避免使用像'ArrayList'这样的实现类型;而是使用界面”。

以下行将更正违规行为:

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

为什么后者使用List代替ArrayList

10 个答案:

答案 0 :(得分:75)

在具体类型上使用接口是良好封装和松散耦合代码的关键。

在编写自己的API时,遵循这种做法甚至是个好主意。如果你这样做,你会发现稍后会更容易将单元测试添加到你的代码中(使用模拟技术),并在将来需要时更改底层实现。

这是关于这个主题的good article

希望它有所帮助!

答案 1 :(得分:28)

这是首选,因为您将代码与列表的实现分离。使用该接口,您可以轻松地将实现(在本例中为ArrayList)更改为另一个列表实现,而无需更改任何其余代码,只要它仅使用List中定义的方法。

答案 2 :(得分:12)

总的来说,我同意将接口与实现分离是一件好事,并且会使代码更易于维护。

但是,您必须考虑例外情况。通过接口访问对象会增加一个额外的间接层,使您的代码变慢。

为了兴趣,我进行了一项实验,该实验产生了对100万长度ArrayList的100亿次顺序访问。在我的2.4Ghz MacBook上,通过List接口访问ArrayList的平均时间为2.10秒,当声明类型为ArrayList时,它平均需要1.67秒。

如果您正在处理大型列表,内部循环内部或经常调用的函数,则需要考虑这一点。

答案 3 :(得分:6)

ArrayList和LinkedList是List的两个实现,它是一个有序的项集合。逻辑方面,如果使用ArrayList或LinkedList并不重要,所以不应该将类型约束为。

这与“收集”和“列表”形成鲜明对比,后者是不同的东西(列表意味着排序,收集不会)。

答案 4 :(得分:2)

  

为什么后者使用List而不是ArrayList?

这是一个很好的做法:程序接口而不是实现

ArrayList替换为List,您可以在以后更改List实施,具体取决于您的业务用例。

List<Object> list = new  LinkedList<Object>(); 
/* Doubly-linked list implementation of the List and Deque interfaces. 
 Implements all optional list operations, and permits all elements (including null).*/

OR

List<Object> list = new  CopyOnWriteArrayList<Object>(); 
/* A thread-safe variant of ArrayList in which all mutative operations
 (add, set, and so on) are implemented by making a fresh copy of the underlying array.*/

OR

List<Object> list = new  Stack<Object>(); 

/* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/

OR

其他一些List具体实现。

List接口定义了合同,List的具体实现可以更改。通过这种方式,接口和实现松散耦合。

相关的SE问题:

What does it mean to "program to an interface"?

答案 5 :(得分:1)

一般来说,对于您的代码行,打扰接口是没有意义的。但是,如果我们谈论API,那就有一个很好的理由。我上了小班

class Counter {
    static int sizeOf(List<?> items) {
        return items.size();
    }
}

在这种情况下,需要使用接口。因为我想计算每个可能的实现的大小,包括我自己的自定义。 class MyList extends AbstractList<String>...

答案 6 :(得分:1)

您的类/接口的属性应该通过接口公开,因为它为您的类提供了一个行为契约,无论其实现如何。

...然而

在局部变量声明中,这样做没有意义:

public void someMethod() {
List theList = new ArrayList();
//do stuff with the list
}

如果是局部变量,只需使用该类型即可。它仍然可以隐式地向上转换为其适当的接口,并且您的方法应该有希望接受其参数的接口类型,但对于局部变量,将实现类型用作容器是完全合理的,以防万一您确实需要实现 - 具体功能。

答案 7 :(得分:1)

即使对于局部变量,使用具体类的接口也有帮助。您最终可能会调用接口外部的方法,然后在必要时很难更改List的实现。 此外,最好在声明中使用最不具体的类或接口。如果元素顺序无关紧要,请使用Collection而不是List。这为您的代码提供了最大的灵活性。

答案 8 :(得分:0)

接口向最终用户公开。一类可以实现多个接口。暴露于特定界面的用户可以访问该特定界面中定义的某些特定行为。

一个接口也有多种实现。基于该方案的系统将与不同的方案一起工作(接口的实现)。

让我知道是否需要更多说明。

答案 9 :(得分:0)

在调试器视图中,接口通常比具体的类具有更好的表示形式。