public class SomeClass {
private HashSet<SomeObject> contents = new HashSet<SomeObject>();
private Set<SomeObject> contents2 = new HashSet<SomeObject>();
}
有什么区别?最后他们都是HashSet
不是吗?第二个看起来对我来说是错的,但我已经看到它经常使用,接受和工作。
答案 0 :(得分:22)
Set
是一个接口,HashSet
是一个实现Set
接口的类。
将变量声明为HashSet
类型意味着不能使用Set
的其他实现。如果您需要HashSet
的特定功能,则可能需要此功能。
如果您不需要HashSet
中的任何特定功能,最好将变量声明为Set
类型。这使得确切的实现可以在以后更改。您可能会发现,对于您正在使用的数据,不同的实现可以更好地工作。通过使用界面,您可以在以后需要时进行此更改。
您可以在此处查看更多详细信息:When should I use an interface in java?
答案 1 :(得分:3)
Set是HashSet实现的集合接口。
第二种选择通常是理想的选择,因为它更通用。
答案 2 :(得分:3)
由于HashSet类实现了Set接口,因此将HashSet分配给Set变量是合法的。但是你不能走另一条路(将一个Set分配给一个更具体的HashSet变量)。
答案 3 :(得分:3)
Set
是HashSet
实现的接口,因此如果您执行此操作:
Set<E> mySet = new HashSet<E>();
您仍然可以访问HashSet
的功能,但您也可以灵活地在将来用另一个Set
类的实例替换具体实例,例如{{1} }或LinkedHashSet
,或其他实现。
第一种方法使用具体类,允许您用自身或子类的实例替换类,但灵活性较低。例如,如果您的变量类型为TreeSet
,则无法使用TreeSet
。
这是约书亚布洛赫Effective Java, 2nd Edition的第52项。
通过接口参阅对象
...您应该倾向于使用接口而不是类来引用对象。 如果存在适当的接口类型,则应使用接口类型声明参数,返回值,变量和字段。您真正需要引用对象类的唯一时间是在创建它时用构造函数......
// 通常很好 - 使用接口作为类型
HashSet
// 通常为Bad - 使用具体类作为类型!
List<T> tlist = new Vector<T>();
这种做法确实带有一些警告 - 如果您想要的实现具有通用接口无法保证的特殊行为,那么您必须相应地记录您的要求。
例如,Vector<T> vec = new Vector<T>();
是Vector<T>
,而synchronized
(也是ArrayList<T>
的实施者)则没有,所以如果您在设计中需要同步容器(或不),你需要记录下来。
答案 4 :(得分:2)
值得一提的是,界面与具体类规则对于API中公开的类型最为重要,例如。方法参数或返回类型。对于私有字段和变量,它只能确保您不使用具体实现中的任何方法(即HashSet),但它是私有的,所以并不重要。
另一件事是添加另一个类型引用会略微增加编译类的大小。大多数人都不在乎,但这些事情加起来。