1

例如,我经常看到这样的:

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>();

前者与后者的优缺点是什么?

4

4 回答 4

2

对我来说,它归结为几点。

你关心执行吗?您的代码是否需要知道Map是 aHashMap还是 a TreeMap?还是它只关心它有某种键/值结构

这也意味着当我构建我的实现代码时,如果我公开一个返回 Map 的方法,我可以随着时间的推移更改实现而不影响任何依赖它的代码(因此尝试强制转换是一个坏主意的原因这些类型的值)

另一个是在代码中移动这些结构变得更容易,这样任何可以接受 a 的方法都将比依赖于 a的方法Map更容易处理HashMap

约定(我遵循的)基本上是使用满足 API 需求的最低功能接口。使用不提供 API 所需功能的接口是没有意义的(例如,如果您需要 a SortedMap,则没有必要使用Mapthen)

恕我直言

于 2012-08-11T03:18:43.753 回答
1

通常,您希望声明具有您实际使用的行为的最通用类型。这样,如果您决定采用不同的具体类,就不必更改太多代码。并且您允许该功能的用户有更多的自由。

于 2012-08-11T03:19:55.750 回答
1

您应该阅读William R. Cook重新访问的On Understanding Data Abstraction以及他的关于“对象”和“面向对象”的简化、现代定义的建议

基本上:如果您将Java 类用作工厂以外的任何东西,即如果您在new运算符之后的任何地方都有一个类名,那么您就不是在进行面向对象的编程。遵循这条规则并不能保证你正在做 OO,但违反这条规则意味着你没有。

注意:不做OO没有错。

于 2012-08-11T04:45:58.527 回答
0

应用程序的维护成本可能是开发成本的三倍。这意味着您希望代码尽可能简单和清晰。

如果您使用 List 而不是 ArrayList,则表明您没有使用 ArrayList 特有的任何方法,并且可以从另一个 List 实现中更改它。在不必使用 ArrayList 时使用的问题是需要很长时间才能安全地确定它确实可能是一个 List。也就是说,很难证明你从来不需要什么东西。(添加东西比删除它相对容易)

一个类似的例子是在 List 可以使用 Vector 时。如果你看到一个 Vector,你会说;开发人员选择 Vector 是有充分理由的,它是线程安全的。但我现在需要更改它并检查代码是否是线程安全的。他们你说,但我看不到它是如何以多线程方式使用的,所以我必须检查它可能使用的所有方式,或者我是否需要在迭代它时添加同步,而实际上它从来不需要是线程安全的。在不需要的时候使用线程安全集合不仅浪费 CPU 时间,更重要的是浪费开发人员的时间。

于 2012-08-11T06:52:47.830 回答