2

我一直看到集合数据结构被实例化为子实例并由它们的父接口声明。例如。

Set<E> collection1 = new HashSet<E>();
Map<E> collection1 = new HashMap<E>();

这背后的原因是什么。子类将继承所有方法,并且 Java 文档中从子类中提到的所有方法都被覆盖但具有相同的含义。那么声明它们的原因是它们的父接口。

任何投入都将极大地帮助我增强我的基础知识。


编辑

感谢您的反馈意见。我明白了。但在改变

Set<E> collection1 = new HashSet<E>();

Set<E> collection1 = new LinkedHashSet<E>();

我们将失去对原始 HashSet 的引用,因为我们正在为引用集声明一个新的 LinkedHashSet。那么这样做有什么意义呢?如果有任何方法可以将旧实现转换为新实现而不会丢失数据,那么这将是有意义的。

4

2 回答 2

4

这称为接口编码。这样做基本上是为了让您稍后可以更改接口的底层实现,而无需对其他地方的代码进行太多更改。您可以稍后替换任何具体的实现。

Set<E> collection1 = new LinkedHashSet<E>();

任何期望接口类型的方法或代码都可以提供其任何实现类型。

根据Effective Java 2nd Edition,第 52 条:通过接口引用对象

如果存在适当的接口类型,则参数、返回值和字段都应使用接口类型声明。如果您养成使用接口类型的习惯,您的程序将会更加灵活。如果不存在适当的接口,则由类引用对象是完全合适的。

这就是Liskov 替换原则所说的:

可替代性是面向对象编程的一个原则。它指出,在计算机程序中,如果 S 是 T 的子类型,则类型 T 的对象可以用类型 S 的对象替换(即,类型 S 的对象可以替换类型 T 的对象)而不改变任何该程序的理想属性(正确性、执行的任务等)。

我相信你的代码不应该依赖于对象的实现细节,而应该依赖于它发布的接口。

于 2013-07-10T04:58:36.847 回答
1

编译器将变量视为抽象类型(例如Set,这意味着您可以稍后在需要时换入新的具体实现(JDK 中的各种 Set 实现之一或您自己的)。

这是一种很好的编程习惯,因为它减少了耦合。

它的正式名称为Liskov 替换原则

于 2013-07-10T05:06:10.863 回答