PMD将报告以下违规行为:

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


违反行为是“避免使用'ArrayList'之类的实现类型;而应使用接口”。

以下行将纠正此违规:

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


为什么应该使用带有List的后者代替ArrayList

评论

另请参见stackoverflow.com/questions/383947/…

#1 楼

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

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

这里有一篇不错的文章主题。

希望有帮助!

评论


而使用“集合”而不是“列表”呢,那么我们在抽象上又走了一步……?

–user1156544
18年5月23日在15:44



#2 楼

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

#3 楼

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

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

为了有趣,我进行了一个实验,该实验产生了对100万个长度ArrayList的100亿次顺序访问。在我的2.4Ghz MacBook上,通过List接口访问ArrayList平均花费2.10秒,而将其声明为ArrayList类型则平均花费1.67秒。

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

评论


@Owen:+5有洞察力的回复:性能差异...非常意外

–安德·特纳(Ande Turner)
08年11月15日在6:39

但是,此答案表明开销可能很小:stackoverflow.com/questions/890687/…

–雷德瓦尔德
2011年11月1日15:10

哇! 100亿次访问需要0.5秒,即1个接口访问比类访问要慢半纳秒!当然,这是永远不要使用接口的原因。

– Ingo
13-10-12在21:47

#4 楼

ArrayList和LinkedList是List的两种实现,它是项目的有序集合。从逻辑上讲,使用ArrayList或LinkedList无关紧要,因此您不应将类型限制为该类型。

这与说Collection和List相反,它们是不同的东西(列表暗含排序,Collection不暗指)。

#5 楼


为什么要使用带有List的后者而不是ArrayList?


这是一个好习惯:程序要接口而不是实现

通过替换q4​​312079q使用ArrayList以后,您可以根据业务用例在将来更改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问题:

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

评论


而使用“集合”而不是“列表”呢,例如,可以使用列表或集合

–user1156544
18年5月23日在15:46

#6 楼

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

#7 楼

您的类/接口的属性应通过接口公开,因为它使您的类可以使用的行为契约,无论其实现如何。

但是...

在本地变量声明,这样做是没有意义的:

public void someMethod() {
List theList = new ArrayList();
//do stuff with the list
}
如果它是局部变量,则只需使用类型。它仍然可以隐式地转换为其适当的接口,并且您的方法应该希望接受其参数的接口类型,但是对于局部变量,将实现类型用作容器是完全有意义的,以防万一您确实需要实现-特定功能。

#8 楼

通常,对于您的代码行,不必理会接口。但是,如果我们谈论的是API,则有充分的理由。我有小类

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


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

评论


如果您对ArrayList之类的实现进行编码,则即使使用接口方法可以做同样的事情,也很可能使用实现方法。这会将您的代码绑定到实现-使得以后在实现之间切换变得更加困难。

–冠军
2011年5月1日晚上8:37

#9 楼

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

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

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

#10 楼

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