hqt*_*hqt 139 java polymorphism interface list
可能重复:
为什么要优先选择Java类的接口?
我应该什么时候使用
List<Object> list = new ArrayList<Object>();
Run Code Online (Sandbox Code Playgroud)
ArrayList
继承自List
,所以如果某些功能ArrayList
不在List
,那么我将失去一些功能ArrayList
,对吧?编译器在尝试访问这些方法时会注意到错误?
Ale*_*ood 244
您这样做的主要原因是将代码与特定的接口实现分离.当你编写这样的代码时:
List list = new ArrayList();
Run Code Online (Sandbox Code Playgroud)
其余的代码只知道数据是类型的List
,这是更好的,因为它允许您List
轻松地在接口的不同实现之间切换.
例如,假设您正在编写一个相当大的第三方库,并说您决定使用一个实现库的核心LinkedList
.如果您的图书馆在很大程度上依赖于访问这些列表中的元素,那么最终您会发现您做出了糟糕的设计决策; 你会意识到你应该使用a ArrayList
(它给出O(1)访问时间)而不是a LinkedList
(它给出O(n)访问时间).假设您已经编程到接口,那么进行这样的更改很容易.你只需要更改List
from 的实例,
List list = new LinkedList();
Run Code Online (Sandbox Code Playgroud)
至
List list = new ArrayList();
Run Code Online (Sandbox Code Playgroud)
并且您知道这将有效,因为您已编写代码以遵循List
接口提供的合同.
另一方面,如果您使用了库的核心LinkedList list = new LinkedList()
,那么进行这样的更改将不会那么容易,因为无法保证您的其余代码不会使用特定于LinkedList
该类的方法.
总而言之,选择只是设计问题......但这种设计非常重要(特别是在处理大型项目时),因为它可以让您在不破坏现有代码的情况下进行特定于实现的更改.
Rei*_*ica 22
这在暴露公共接口时也很有用.如果你有这样的方法,
public ArrayList getList();
Run Code Online (Sandbox Code Playgroud)
然后你决定改成它,
public LinkedList getList();
Run Code Online (Sandbox Code Playgroud)
任何正在做的人ArrayList list = yourClass.getList()
都需要更改他们的代码.另一方面,如果你这样做,
public List getList();
Run Code Online (Sandbox Code Playgroud)
更改实施不会改变API用户的任何内容.
小智 11
我认为@ tsatiz的答案大多是正确的(编程到接口而不是实现).但是,通过对接口进行编程,您不会丢失任何功能.让我解释.
如果将变量声明为a
,则实际上不会丢失ArrayList的任何功能.所有你需要做的就是把你List<type> list = new ArrayList<type>
list
归结为一个ArrayList
.这是一个例子:
List<String> list = new ArrayList<String>();
((ArrayList<String>) list).ensureCapacity(19);
Run Code Online (Sandbox Code Playgroud)
最终我认为tsatiz是正确的,因为一旦你转换为ArrayList,你就不再编码到接口了.但是,最初编写接口代码仍然是一种很好的做法,如果必要的话,如果以后需要,则编写实现代码.
希望有所帮助!
这使您可以编写如下内容:
void doSomething() {
List<String>list = new ArrayList<String>();
//do something
}
Run Code Online (Sandbox Code Playgroud)
稍后,您可能希望将其更改为:
void doSomething() {
List<String>list = new LinkedList<String>();
//do something
}
Run Code Online (Sandbox Code Playgroud)
无需更改方法的其余部分.
但是,如果你想使用CopyOnWriteArrayList
例如,你需要声明它,如果你想使用它的额外方法(例如addIfAbsent),则不需要声明它:
void doSomething() {
CopyOnWriteArrayList<String>list = new CopyOnWriteArrayList<String>();
//do something, for example:
list.addIfAbsent("abc");
}
Run Code Online (Sandbox Code Playgroud)
每当我不想增加问题的复杂性时,我就会使用这种结构.它只是一个列表,不需要说明它是什么类型的列表,因为它与问题无关.我经常在我的大多数解决方案中使用Collection,因为最终,对于软件的其余部分,最重要的是它所拥有的内容,我不想在集合中添加新对象. .
此外,当您认为您可能想要更改正在使用的列表的实现时,可以使用该构造.假设您正在使用带有ArrayList的构造,并且您的问题不是线程安全的.现在,您希望使其成为线程安全的,并且对于部分解决方案,您可以更改为使用Vector.至于该列表的其他用途无关紧要,如果它是AraryList或Vector,只是一个List,则不需要新的修改.
我想你问题的核心是为什么 program to an interface, not to an implementation
只是因为一个接口为您提供了更多抽象,并使代码更灵活,更灵活,因为您可以使用相同接口的不同实现(在这种情况下,您可能希望将List实现更改为linkedList而不是ArrayList)没有改变它的客户.