Set:不可重复
Set也是Collection接口的子接口,但是与Collection或List接口不同的是,Set中不能加入重复的元素,它适用于存储无序且值不相等的元素(依靠Object类中的equals()和hashCode()方法来区分是否是同一个对象)。可以依据该体系集合知道某物是否已经存在于集合中。常用的子类是HashSet、TreeSet以及LinkedHashSet 这里要单独介绍一下对象的相等性:
- 对象的相等性在本质上是对象的HashCode值相等,Java依据对象的内存地址计算出对象的HashCode值。
- 如果需要比较两个对象是否相等,则必须同时覆盖对象的hashCode方法和equals方法,并且hashCode方法和equals方法的返回值必须相同。即首先调用hashCode()比较要加入的对象与已经存在的对象的hashcode值,如果不存在相等的hashcode值,则不存在与要加入对象相等的对象,可以加入该对象;如果存在相等的hashcode值,则调用equals()检查hashcode相等的对象是否真的相等,如果两者相等,则要加入的对象已经存在了,加入操作就不会发生。
- 如果一个类没有覆盖hashCode()和equals()方法,则它的equals()方法执行的是引用相等性的比较。
下面附生活中的例子对HashCode进行理解: 例如:在生活中,每个人都有一个唯一的身份证号,当进行登车入口审查时,肯定先检查身份证号是否一致(相当于使用hashCode),如果一致的话,则再将每个人的具体信息进行匹配(相当于对象比较使用equals()),如果全部符合,则表示通过审查。
1. HashSet:散列存放,无序,HashMap实现
HashSet是Set接口的一个子类,主要的特点是:里面不能存放重复元素,而且采用散列的存储方式,所以没有顺序。同时,HashSet只是不保证有序,并不是保证无序。下面是代码案例: )
2. TreeSet:有序的存放,二叉树实现
TreeSet基于二叉树的原理对新添加的对象按照指定的顺序排序(升序、降序),每添加一个对象都会进行排序,并将对象插入二叉树指定的位置。 这里关于TreeSet排序做出说明: 既然TreeSet本身是可以排序的,那么现在自定义一个数据类型是否也可以进行拍讯的操作呢? 以上程序代码出现了类转换异常,出现这样的问题,是因为TreeSet中的元素是有序存放,所以对于一个对象必须要指定好其排序规则,且TreeSet中的每个对象所在的类都必须实现Comparable接口才可以正常使用。若覆写compare函数,则在升序时在this.对象小于指定对象的条件下返回-1,在降序时在this.对象大于指定对象的条件返回1。下面我来对Person对象指定排序规则(通过年龄排序并增加字符串的比较):
3. LinkedHashSet:继承HashSet,HashMap实现数据存储,双向链表记录顺序
LinkedHashSet是HashSet的一个“扩展版本”,HashSet并不管什么顺序,而LinkedHashSet会维护“插入顺序”。HashSet内部使用HashMap对象来存储它的元素,而LinkedHashSet内部使用LinkedHashMap对象来存储和处理它的元素,它继承了HashSet,所有的方法和操作都与HashSet相同,因此LinkedHashSet的实现比较简单,只提供了4个构造方法(4个构造函数调用的是同一个父类的构造函数),并通过传递一个标识参数调用父类的构造器,在底层构造一个LinkedHashMap来记录数据访问,其他相关操作与父类HashSet相同,直接调用父类HashSet的方法即可。
4. 关于Set的面试问题
- List和Set的区别是什么? List可以包含重复的元素,而Set只能包含不同的元素。
- Set如何保证元素不重复? set在插入数据时,先比较hashCode:如果hashCode相同才会比较equals,equals相同,则两个对象相同,不能插入,equals不同,可以插入;如果hashCode不同,就直接插入了,两个对象hashCode不相等,他们equals一定是false。