例如,我经常看到这个:
Set<Integer> s = new TreeSet<Integer>();
Set<Integer> s = new HashSet<Integer>();
Map<Integer, String> m = new HashMap<Integer, String>();
结束
TreeSet<Integer> ts = new TreeSet<Integer>();
HashSet<Integer> hs = new HashSet<Integer>();
HashMap<Integer, String> hm = new HashMap<Integer, String>();
前者与后者的优点/缺点是什么?
答案 0 :(得分:2)
对我来说,这可以归结为一些观点。
你关心实施吗?您的代码是否需要知道Map
是HashMap
还是TreeMap
?或者只是关心它有某种键/值结构
这也意味着当我构建我的实现代码时,如果我公开一个返回Map的方法,我可以随着时间的推移改变实现,而不会影响任何依赖它的代码(因此,这是一个坏主意的原因)尝试投射这些类型的值)
另一个是在代码周围移动这些结构变得更容易,这样任何可以接受Map
的方法都会更容易处理,然后依赖于HashMap
例如
约定(我遵循)基本上是使用满足API需求的最低功能接口。没有必要使用不提供API所需功能的界面(例如,如果您需要SortedMap
,那么使用Map
就没有意义了)
IMHO
答案 1 :(得分:1)
通常,您希望声明具有您实际使用的行为的最常规类型。这样,如果您决定采用不同的具体类,则无需更改尽可能多的代码。并且您允许该功能的用户更自由。
答案 2 :(得分:1)
您应该On Understanding Data Abstraction, Revisited和他的William R. Cook阅读Proposal for Simplified, Modern Definitions of "Object" and "Object Oriented"。
基本上:如果你将Java类用作工厂之外的其他东西,即如果你在new
运算符之后有任何期望的类名,那么你就不会进行面向对象的编程。遵循此规则并不保证您正在执行OO,但违反此规则意味着您不是。
注意:不做OO没有错。
答案 3 :(得分:0)
应用程序的维护成本可能是开发的三倍。这意味着您希望代码尽可能简单明了。
如果使用List而不是ArrayList,则表明您没有使用任何特殊于ArrayList的方法,并且可以从另一个List实现更改它。使用ArrayList的问题不一定是需要很长时间才能安全地确定它本来可以是List。即很难证明你从来不需要什么。 (添加内容比删除内容相对容易)
类似的例子是在List执行时使用Vector。如果你看到一个Vector你说;开发人员选择Vector是有充分理由的,它是线程安全的。但我现在需要更改它并检查代码是否是线程安全的。你说,但是我看不出它是如何以多线程方式使用的,所以我必须检查它可能使用的所有方式,或者当我迭代它时实际上它从不需要时我需要添加同步是线程安全的。在不需要时使用线程安全集合不仅浪费CPU时间,更重要的是浪费开发人员的时间。