声明为父接口并初始化为子实例

时间:2013-07-10 04:58:07

标签: java collections hashmap hashset

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

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。那么这样做有什么意义呢? 如果我们可以通过任何方式将旧实现转换为新实现而不丢失数据,那么这将是有意义的。

2 个答案:

答案 0 :(得分:4)

这称为接口编码。这基本上已经完成,以便您可以稍后更改接口的底层实现,而无需在其他地方更改代码。您可以稍后替换任何具体的实现。

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

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

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

  

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

这是Liskov substitution principle所说的:

  

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

有些我认为您的代码不应该依赖于对象的实现细节,只需要它的已发布界面。

答案 1 :(得分:1)

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

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

它正式名称为Liskov substitution principle