为什么一个Java类的接口是首选?

PMD将报告违规行为:

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

违规是“避免使用像'ArrayList'的实现类型;使用接口,而不是”。

以下行将纠正违规行为:

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

为什么要用List来代替ArrayList呢?

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

在编写自己的API时遵循这个习惯甚至是一个好主意。 如果你这样做了,你会发现稍后你可以更容易地向你的代码添加单元测试(使用Mocking技术),并在将来需要的时候改变底层的实现。

这是一个关于这个问题的好文章 。

希望它有帮助!

这是首选,因为你将代码从列表的实现中分离出来。 使用这个接口,你可以很容易地将实现ArrayList(在这种情况下)改变为另一个列表实现,而不用改变其余的代码,只要它使用List中定义的方法即可。

一般来说,我同意将接口从实现中解耦是一件好事,并且会使代码更容易维护。

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

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

如果您正在处理大型列表,深入内部循环或经常调用的函数,那么这是需要考虑的事情。

ArrayList和LinkedList是List的两个实现,它是一个有序的项目集合。 逻辑方面,如果你使用ArrayList或者LinkedList,那么不要紧,所以你不应该把类型限制为那个类型。

这与Collection和List是不同的东西(List意味着排序,Collection不意味着对比)。

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

你的类/接口的属性应该通过接口公开,因为它给你的类使用一个行为的合约,而不管实现如何。

然而…

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

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

如果它是一个局部变量,就使用这个类型。 对于它的适当的接口,它仍然是隐式的可接受的,你的方法应该希望接受它的参数的接口类型,但是对于局部变量,使用实现类型作为容器是完全合理的,以防万一你需要实现 – 具体的功能。

为什么要用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).*/ 

要么

 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.*/ 

要么

 List<Object> list = new Stack<Object>(); /* The Stack class represents a last-in-first-out (LIFO) stack of objects.*/ 

要么

其他一些List具体实现。

List接口定义合同, List具体实现可以改变。 这样, 接口和实现是松散耦合的。

相关的SE问题:

什么意思是“编程接口”?

Spring框架非常适用接口的概念 – http://www.springframework.org/

Spring通过配置文件将实现提供给一个具体的类,因此具体类对于实现不需要知道任何东西。

Spring的研究体现了Java中基于接口的编程的优点。

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

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

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