为什么在 Java 中用接口名称来声明变量?
这是一个真正的初学者问题(我仍在学习 Java 基础知识)。
我可以(某种程度上)理解为什么方法会返回 List
我不明白的是:创建这样的局部变量似乎是常见的做法:
List<String> list = new ArrayList<String>();
虽然这种形式不太常见:
ArrayList<String> list = new ArrayList<String>();
这里有什么优点?
我所能看到的只是一个小缺点:必须为 java.util.List 添加单独的“导入”行。从技术上讲,可以使用“import java.util.*”,但我也不经常看到这种情况,可能是因为“import”行是由某些 IDE 自动添加的。
This is a real beginner question (I'm still learning the Java basics).
I can (sort of) understand why methods would return a List<String> rather than an ArrayList<String>, or why they would accept a List parameter rather than an ArrayList. If it makes no difference to the method (i.e., if no special methods from ArrayList are required), this would make the method more flexible, and easier to use for callers. The same thing goes for other collection types, like Set or Map.
What I don't understand: it appears to be common practice to create local variables like this:
List<String> list = new ArrayList<String>();
While this form is less frequent:
ArrayList<String> list = new ArrayList<String>();
What's the advantage here?
All I can see is a minor disadvantage: a separate "import" line for java.util.List has to be added. Technically, "import java.util.*" could be used, but I don't see that very often either, probably because the "import" lines are added automatically by some IDE.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
当您阅读时,
您会发现您所关心的只是一个
List
并且您不太重视实际实现。此外,您将自己限制为由List
声明的成员,而不是特定的实现。您并不关心数据是否存储在线性数组或某种奇特的数据结构中,只要它看起来像List
即可。另一方面,阅读第二行会让您知道代码关心变量是
ArrayList
。通过编写此内容,您(对未来的读者)隐含地告诉您,您不应该盲目地更改实际的对象类型,因为代码的其余部分依赖事实,即它实际上是一个ArrayList<字符串>
。When you read
you get the idea that all you care about is being a
List<String>
and you put less emphasis on the actual implementation. Also, you restrict yourself to members declared byList<String>
and not the particular implementation. You don't care if your data is stored in a linear array or some fancy data structure, as long as it looks like aList<String>
.On the other hand, reading the second line gives you the idea that the code cares about the variable being
ArrayList<String>
. By writing this, you are implicitly saying (to future readers) that you shouldn't blindly change actual object type because the rest of the code relies on the fact that it is really anArrayList<String>
.使用该接口可以让您快速更改List/Map/Set等的底层实现。
这不是为了节省击键次数,而是为了快速改变实现。理想情况下,您不应公开实现的底层特定方法,而只需使用所需的接口。
Using the interface allows you to quickly change the underlying implementation of the List/Map/Set/etc.
It's not about saving keystrokes, it's about changing implementation quickly. Ideally, you shouldn't be exposing the underlying specific methods of the implementation and just use the interface required.
我建议从另一端考虑这个问题。通常您需要一个列表或集合或任何其他集合类型 - 并且您实际上并不关心代码中它是如何实现的。因此,您的代码只适用于列表并执行它需要执行的任何操作(也称为“始终向接口编写代码”)。
当您创建列表时,您需要决定您想要的实际实现。对于大多数用途来说,ArrayList“足够好”,但您的代码确实不在乎。通过坚持使用界面,您可以将这一点传达给未来的读者。
例如,我习惯在主方法中添加调试代码,将系统属性转储到 System.out - 通常对它们进行排序会更好。最简单的方法是简单地让“Map map = new TreeMap(properties);”然后迭代它们,因为 TreeMap 返回已排序的键。
当您了解有关 Java 的更多信息时,您还会发现接口对于测试和模拟非常有帮助,因为您可以创建具有在运行时指定的行为且符合给定接口的对象。高级(但简单)示例可以在 http://www .exampledepot.com/egs/java.lang.reflect/ProxyClass.html
I would suggest thinking about this from the other end around. Usually you want a List or a Set or any other Collection type - and you really do not care in your code how exactly this is implemented. Hence your code just works with a List and do whatever it needs to do (also phrased as "always code to interfaces").
When you create the List, you need to decide what actual implementation you want. For most purposes ArrayList is "good enough", but your code really doesn't care. By sticking to using the interface you convey this to the future reader.
For instance I have a habit of having debug code in my main method which dumps the system properties to System.out - it is usually much nicer to have them sorted. The easiest way is to simply let "Map map = new TreeMap(properties);" and THEN iterate through them, as TreeMap returns the keys sorted.
When you learn more about Java, you will also see that interfaces are very helpful in testing and mocking, since you can create objects with behaviour specified at runtime conforming to a given interface. An advanced (but simple) example can be seen at http://www.exampledepot.com/egs/java.lang.reflect/ProxyClass.html
如果稍后您想更改列表的实现并使用例如 LinkedList(也许是为了更好的性能),您不必更改整个代码(以及 API,如果它的库)。如果顺序无关紧要,您应该返回 Collection,以便稍后如果需要对项目进行排序,您可以轻松地将其更改为 Set。
if later you want to change implementation of the list and use for example LinkedList(maybe for better performance) you dont have to change the whole code(and API if its library). if order doesnt matter you should return Collection so later on you can easily change it to Set if you would need items to be sorted.
我能想到的最好的解释(因为我不像其他语言那样频繁地使用 Java 进行编程)是,它可以更轻松地更改“后端”列表类型,同时保持其他所有内容相同的代码/界面依靠。如果您首先将其声明为更具体的类型,然后再决定需要不同的类型...如果碰巧使用 ArrayList 特定的方法,那就是额外的工作。
当然,如果您确实需要 ArrayList 特定的行为,则可以使用特定的变量类型。
The best explanation I can come up with (because I don't program in Java as frequently as in other languages) is that it make it easier to change the "back-end" list type while maintaining the same code/interface everything else is relying on. If you declare it as a more specific type first, then later decide you want a different kind... if something happens to use an ArrayList-specific method, that's extra work.
Of course, if you actually need ArrayList-specific behavior, you'd go with the specific variable type instead.
重点是确定您想要/需要的行为,然后使用提供该行为的接口。这是您的变量的类型。然后,使用满足您其他需求的实现——效率等。这就是您用“new”创建的。这种二元性是 OOD 背后的主要思想之一。当您处理局部变量时,这个问题并不是特别重要,但始终遵循良好的编码实践并没有什么坏处。
The point is to identify the behavior you want/need and then use the interface that provides that behavior. The is the type for your variable. Then, use the implementation that meets your other needs - efficiency, etc. This is what you create with "new". This duality is one of the major ideas behind OOD. The issue is not particularly significant when you are dealing with local variables, but it rarely hurts to follow good coding practices all the time.
基本上,这来自那些必须运行大型项目的人,可能还有其他原因——你总是听到这样的说法。为什么,我其实不知道。如果您需要数组列表,或哈希映射或哈希集或其他任何东西,我认为通过转换为接口来消除方法没有意义。
举个例子,最近我学习了如何使用和实现 HashSet 作为一个主要的数据结构。假设,无论出于什么原因,我去一个团队工作。难道那个人不需要知道数据是基于散列方法而不是按某种基础排序吗? Twisol 指出的后端方法适用于 C/C++,您可以公开标头并出售库,因此,如果有人知道如何在 Java 中做到这一点,我想他们会使用 JNI - 在这一点上对我来说似乎更简单使用 C/C++,您可以公开标头并使用为此目的建立的工具构建库。
当你找到可以在扩展目录中安装 jar 文件的人时,在我看来,该实体可能仅几步之遥 - 我在扩展目录中放置了几个加密库,这很方便,但我真的很喜欢看到一个清晰、简洁的基础阐明。我想他们一直都这样做。
在我看来,这听起来像是经典的混淆,但要注意:在问题产生后果之前,您需要进行一些编码。
Basically this comes from people who have to run large projects, possibly other reasons - you hear it all the time. Why, I don't actually know. If you have need of an array list, or Hash Map or Hash Set or whatever else I see no point in eliminating methods by casting to an interface.
Let us say for example, recently I learned how to use and implemented HashSet as a principle data structure. Suppose, for whatever reason, I went to work on a team. Would not that person need to know that the data was keyed on hashing approaches rather than being ordered by some basis? The back-end approach noted by Twisol works in C/C++ where you can expose the headers and sell a library thus, if someone knows how to do that in Java I would imagine they would use JNI - at which point is seems simpler to me to use C/C++ where you can expose the headers and build libs using established tools for that purpose.
By the time you can get someone who can install a jar file in the extensions dir it would seem to me that entity could be jus short steps away - I dropped several crypto libs in the extensions directory, that was handy, but I would really like to see a clear, concise basis elucidated. I imagine they do that all the time.
At this point it sounds to me like classic obfuscation, but beware: You have some coding to do before the issue is of consequence.