为什么应该首选Java类的接口?
PMD将报告以下违规行为:
ArrayList<Object> list = new ArrayList<Object>();
违反情况是"避免使用类似'ArrayList'的实现类型;而应使用接口"。
以下行将纠正违规:
List<Object> list = new ArrayList<Object>();
为什么要使用带有List的后者而不是ArrayList?
解决方案
这是首选方法,因为我们可以将代码与列表的实现脱钩。使用该接口,我们可以轻松地将实现(在这种情况下为ArrayList)更改为另一个列表实现,而无需更改任何其余代码,只要它仅使用List中定义的方法即可。
在具体类型上使用接口是实现良好封装和松散耦合代码的关键。
在编写自己的API时遵循这种做法甚至是个好主意。如果这样做,以后我们会发现,将单元测试添加到代码中(使用Mocking技术),并在将来需要时更改基础实现会更容易。
这是一篇关于该主题的好文章。
希望能帮助到你!
ArrayList和LinkedList是List的两种实现,它是项目的有序集合。从逻辑上讲,使用ArrayList或者LinkedList无关紧要,因此我们不应将类型限制为该类型。
这与说Collection和List相反,后者是不同的东西(List表示排序,Collection不是)。
通常,对于代码行,不必理会接口。但是,如果我们谈论的是API,则有充分的理由。我上小班
class Counter { static int sizeOf(List<?> items) { return items.size(); } }
在这种情况下,需要使用接口。因为我想计算每个可能的实现(包括我自己的自定义)的大小。 "类MyList扩展AbstractList <String> ..."。
类/接口的属性应该通过接口公开,因为它使类可以使用的行为契约,而与实现无关。
然而...
在局部变量声明中,这样做没有什么意义:
public void someMethod() { List theList = new ArrayList(); //do stuff with the list }
如果它是局部变量,则只需使用类型。它仍然可以隐式地转换为其适当的接口,方法应该希望为其参数接受接口类型,但是对于局部变量,将实现类型用作容器是完全有意义的,以防万一我们确实需要实现-特定功能。
总的来说,我同意将接口与实现分离是一件好事,它将使代码更易于维护。
但是,我们必须考虑一些例外情况。通过接口访问对象会增加一个间接层,这会使代码变慢。
出于兴趣,我进行了一个实验,该实验生成了对100万个长度的ArrayList的100亿个顺序访问。在我的2.4Ghz MacBook上,通过List接口访问ArrayList平均花费2.10秒,而将其声明为ArrayList类型则平均花费1.67秒。
如果要处理大型列表,深入内部循环或者经常调用的函数,则需要考虑这一点。
即使对于局部变量,在具体类上使用接口也会有所帮助。我们可能最终会调用接口外部的方法,然后如果需要,很难更改List的实现。
另外,最好在声明中使用最不具体的类或者接口。如果元素顺序无关紧要,请使用Collection而不是List。这为代码提供了最大的灵活性。
Spring框架确实很好地应用了接口的概念http://www.springframework.org/
Spring通过配置文件将实现提供给具体类,因此具体类完全不需要了解任何实现。
对Spring的研究证明了Java中基于接口的编程的优势。