这两个java变量声明有什么区别?

public class SomeClass { private HashSet contents = new HashSet(); private Set contents2 = new HashSet(); } 

有什么不同? 到底他们都是HashSet不是吗? 第二个看起来对我来说是错的,但我已经看到它经常使用,接受和工作。

Set是一个接口, HashSet是一个实现Set接口的类。

将变量声明为类型HashSet意味着不能使用Set其他实现。 如果您需要HashSet特定function,则可能需要此function。

如果您不需要HashSet任何特定function,最好将变量声明为Set类型。 这使得确切的实现可以在以后更改。 您可能会发现,对于您正在使用的数据,不同的实现可以更好地工作。 通过使用该界面,您可以在以后根据需要进行此更改。

你可以在这里看到更多细节: 我什么时候应该在java中使用接口?

Set是HashSet实现的集合接口。

第二种选择通常是理想的选择,因为它更通用。

由于HashSet类实现了Set接口,因此将HashSet分配给Set变量是合法的。 但是你不能采用其他方式(将Set分配给更具体的HashSet变量)。

SetHashSet实现的接口,所以如果你这样做:

Set mySet = new HashSet();

您仍然可以访问HashSet的function,但您也可以灵活地将具体实例替换为将来另一个Set类的实例,例如LinkedHashSetTreeSet ,或其他实现。

第一种方法使用具体类,允许您使用自身或子类的实例替换类,但灵活性较低。 例如,如果您的变量类型是HashSet则无法使用TreeSet

这是Joshua Bloch的Effective Java,第2版的第52项。

按其接口引用对象

…您应该支持使用接口而不是类来引用对象。 如果存在适当的接口类型,则应使用接口类型声明参数,返回值,变量和字段。 您真正需要引用对象类的唯一时间是使用构造函数创建它…

// 通常很好 – 使用接口作为类型

List tlist = new Vector();

// 通常很糟糕 – 使用具体类作为类型!

Vector vec = new Vector();

这种做法确实带有一些警告 – 如果您想要的实现具有通用接口无法保证的特殊行为,那么您必须相应地记录您的要求。

例如, Vectorsynchronized ,而ArrayList (也是List的实现者)则没有,因此如果您在设计中需要同步容器(或不需要),则需要记录该容器。

值得一提的是,界面与具体类规则对API中公开的类型最为重要,例如。 方法参数或返回类型。 对于私有字段和变量,它只能确保您不使用具体实现中的任何方法(即HashSet),但它是私有的,因此并不重要。

另一件事是添加另一个类型引用会略微增加编译类的大小。 大多数人都不在乎,但这些东西加起来。