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

Why are variables declared with their interface name in Java?

本问题已经有最佳答案,请猛点这里访问。

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

我可以理解为什么方法会返回list而不是arraylist,或者为什么它们会接受list参数而不是arraylist。如果它对方法没有任何影响(即,如果不需要来自arraylist的特殊方法),这将使方法更灵活,更容易用于调用方。同样的事情也适用于其他集合类型,如集合或映射。

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

1
List<String> list = new ArrayList<String>();

虽然此表单的频率较低:

1
ArrayList<String> list = new ArrayList<String>();

这里的优势是什么?

我所看到的只是一个小缺点:必须为java.util.list添加一个单独的"导入"行。在技术上,可以使用"导入java. U.L.*",但我也不经常看到这一点,这可能是因为"导入"行是由IDE自动添加的。


当你阅读

1
List<String> list = new ArrayList<String>();

您得到的想法是,您所关心的只是一个List,而您对实际实现的重视较少。另外,您将自己限制在List声明的成员,而不是特定的实现。你不在乎你的数据是存储在一个线性数组中还是一些复杂的数据结构中,只要它看起来像一个List

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


使用该接口可以快速更改列表/映射/集等的底层实现。

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


我建议从另一个角度来考虑这个问题。通常,您需要一个列表、一个集合或任何其他集合类型——而您真正不关心代码中实现这一点的精确性。因此,您的代码只与一个列表一起工作,并做它需要做的任何事情(也被称为"总是代码到接口")。

创建列表时,需要决定需要什么实际实现。在大多数情况下,arraylist是"足够好的",但您的代码实际上并不关心。通过坚持使用界面,您可以将这一点传达给未来的读者。

例如,我有一个习惯,在我的主要方法中使用调试代码,将系统属性转储到system.out中——通常对它们进行排序要好得多。最简单的方法是简单地让"map map=new treemap(properties);",然后遍历它们,因为treemap返回排序的键。

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


我能想出的最好的解释(因为我不像其他语言那样频繁地在Java中编程),它使得改变"后端"列表类型更容易,同时保持了其他所有依赖的代码/接口。如果你先声明它是一个更具体的类型,然后决定你想要一个不同的类型…如果有什么事情碰巧使用数组列表特定的方法,那是额外的工作。

当然,如果您实际上需要特定于arraylist的行为,您可以使用特定的变量类型。


如果以后您想更改列表的实现,并使用例如LinkedList(也许是为了提高性能),那么就不必更改整个代码(如果它的库是API)。如果订单不重要,您应该返回集合,这样以后您可以很容易地将其更改为设置,如果您需要对项目进行排序。


重点是识别您想要/需要的行为,然后使用提供该行为的接口。是变量的类型。然后,使用满足您其他需求的实现——效率等等,这就是您用"新"创建的。这种二元性是伍德背后的主要思想之一。当您处理局部变量时,这个问题并不是特别重要,但是始终遵循良好的编码实践很少会造成伤害。


基本上,这来自于那些必须运行大型项目的人,可能还有其他原因——你一直都在听。为什么,我不知道。如果您需要一个数组列表、散列映射、散列集或其他什么东西,我认为通过强制转换到接口来消除方法是没有意义的。

例如,最近我学习了如何使用和实现hashset作为一个原则数据结构。假设,不管出于什么原因,我去了一个团队。那个人难道不需要知道数据是通过散列方法键入的,而不是根据某种基础进行排序吗?TeSISOL注意到的后端方法在C/C++中可以公开标题并销售库,如果有人知道如何在Java中实现这一点,我想他们会使用JNI——在这点上,我似乎更简单地使用C/C++,在这里,您可以使用所建立的工具公开标题和构建LIBs。

当你找到一个可以在extensions目录中安装jar文件的人时,在我看来,这个实体离我只有很短的一步之遥——我在extensions目录中删除了几个加密lib,这很方便,但我真的希望看到一个清晰、简洁的基础被阐明。我想他们总是这样做。

在这一点上,我觉得这听起来像是经典的混淆,但要注意:在问题出现之前,您需要做一些编码工作。