为什么在Java中使用接口名称声明变量?

这是一个真正的初学者问题(我还在学习Java基础知识)。

我可以(有点)理解为什么方法会返回List 而不是ArrayList ,或者为什么它们会接受List参数而不是ArrayList。 如果它对方法没有影响(即,如果不需要ArrayList中的特殊方法),这将使该方法更灵活,更容易用于调用者。 其他集合类型也是如此,例如Set或Map。

我不明白的是:通常的做法是创建这样的局部变量:

List list = new ArrayList(); 

虽然这种forms不太常见:

 ArrayList list = new ArrayList(); 

这有什么好处?

我只能看到一个小缺点:必须添加java.util.List的单独“import”行。 从技术上讲,可以使用“import java.util。*”,但我也不经常看到,可能是因为某些IDE自动添加了“import”行。

当你读

 List list = new ArrayList(); 

你明白你所关心的只是一个List ,你不太重视实际的实现。 此外,您将自己限制为List声明的成员,而不是特定的实现。 您不关心数据是存储在线性数组还是某种奇特的数据结构中,只要它看起来像List

另一方面,阅读第二行可以让您了解代码关心的变量是ArrayList 。 通过编写本文,您隐含地(对未来的读者)说,您不应盲目地更改实际的对象类型,因为其余的代码依赖于它实际上是一个ArrayList这一事实。

使用该界面可以快速更改List / Map / Set / etc的底层实现。

这不是关于保存击键,而是关于快速改变实施。 理想情况下,您不应该公开实现的基础特定方法,只需使用所需的接口。

我建议从另一端考虑这个问题。 通常你需要List或Set或任何其他Collection类型 – 你真的不在乎你的代码如何实现它。 因此,您的代码只适用于List并执行它需要做的任何事情(也称为“始终代码接口”)。

创建 List时,需要确定所需的实际实现。 对于大多数用途,ArrayList“足够好”,但您的代码实际上并不在意。 通过坚持使用界面,您可以将其传达给未来的读者。

例如,我习惯在main方法中使用调试代码将系统属性转储到System.out – 通常将它们排序更好。 最简单的方法是简单地让“Map map = new TreeMap(properties);” 然后迭代它们,因为TreeMap返回已排序的键。

当您了解有关Java的更多信息时,您还将看到接口在测试和模拟方面非常有用,因为您可以创建在运行时指定的行为符合给定接口的对象。 在http://www.exampledepot.com/egs/java.lang.reflect/ProxyClass.html上可以看到一个高级(但简单)的示例

如果以后你想要更改列表的实现并使用例如LinkedList(可能为了更好的性能),你不必更改整个代码(和API,如果它的库)。 如果订单无关紧要,您应该返回Collection,以便稍后您可以轻松地将其更改为Set,如果您需要对项目进行排序。

我能想到的最好的解释(因为我不像其他语言那样频繁地用​​Java编程)是因为它可以更容易地改变“后端”列表类型,同时保持相同的代码/接口,其他一切都是依靠。 如果你首先将它声明为一个更具体的类型,那么后来决定你想要一个不同的类型……如果发生某些事情使用特定于ArrayList的方法,这是额外的工作。

当然,如果您确实需要特定于ArrayList的行为,那么您将使用特定的变量类型。

关键是要确定您想要/需要的行为,然后使用提供该行为的界面。 这是变量的类型。 然后,使用满足您其他需求的实现 – 效率等。这是您使用“new”创建的。 这种二元性是OOD背后的主要思想之一。 当你处理局部变量时,问题并不是特别重要,但是一直遵循良好的编码实践很少会受到伤害。

基本上这来自于那些必须经营大项目的人,可能还有其他原因 – 你一直都在听。 为什么,我实际上不知道。 如果你需要一个数组列表,或者Hash Map或Hash Set或者其他什么,我认为通过强制转换为接口来消除方法毫无意义。

比方说,最近我学会了如何使用和实现HashSet作为主要数据结构。 无论出于何种原因,我假设我去了一个团队工作。 那个人不是必须知道数据是以哈希方法为基础而不是按某种方式排序吗? Twisol提到的后端方法在C / C ++中工作,你可以在这里公开头文件并卖掉一个库,如果有人知道如何用Java做这个,我想他们会使用JNI – 这点对我来说似乎更简单使用C / C ++,您可以使用已建立的工具公开头文件并构建库。

当你可以找到一个可以在扩展目录中安装jar文件的人时,在我看来,实体可能只是很短的步骤 – 我在扩展目录中删除了几个加密库,这很方便,但我真的很喜欢看到一个清晰,简洁的基础阐明。 我想他们一直这样做。

在这一点上,它听起来像经典的混淆,但要注意:在问题发生之前,你需要做一些编码。