这两个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变量)。
Set
是HashSet
实现的接口,所以如果你这样做:
Set
您仍然可以访问HashSet
的function,但您也可以灵活地将具体实例替换为将来另一个Set
类的实例,例如LinkedHashSet
或TreeSet
,或其他实现。
第一种方法使用具体类,允许您使用自身或子类的实例替换类,但灵活性较低。 例如,如果您的变量类型是HashSet
则无法使用TreeSet
。
这是Joshua Bloch的Effective Java,第2版的第52项。
按其接口引用对象
…您应该支持使用接口而不是类来引用对象。 如果存在适当的接口类型,则应使用接口类型声明参数,返回值,变量和字段。 您真正需要引用对象类的唯一时间是使用构造函数创建它…
// 通常很好 – 使用接口作为类型
List
tlist = new Vector (); // 通常很糟糕 – 使用具体类作为类型!
Vector
vec = new Vector ();
这种做法确实带有一些警告 – 如果您想要的实现具有通用接口无法保证的特殊行为,那么您必须相应地记录您的要求。
例如, Vector
是synchronized
,而ArrayList
(也是List
的实现者)则没有,因此如果您在设计中需要同步容器(或不需要),则需要记录该容器。
值得一提的是,界面与具体类规则对API中公开的类型最为重要,例如。 方法参数或返回类型。 对于私有字段和变量,它只能确保您不使用具体实现中的任何方法(即HashSet),但它是私有的,因此并不重要。
另一件事是添加另一个类型引用会略微增加编译类的大小。 大多数人都不在乎,但这些东西加起来。