文章目录
1.Set系列集合特点
1.1 与List比较
List:有序,可重复,有索引
Set:无序,不重复,无索引
1.2 HashSet
添加的元素无序,不重复,无索引。内部数据结构是哈希表,是不同步的。
1.3 LinkedHashSet
添加的元素,有序,不重复,无索引。
1.4 TreeSet
按照大小默认升序排序,不重复,无索引。
关于排序:
-
字符串按照首字符排序。首字符相同时,看第二位,依此类推。
-
有值特性的元素(int,float等),按照数值大小排序。
-
自定义的引用类型,可以:
--------- 在对象类中重写Comparable接口的compareTo()方法。
--------- 为集合设置比较器对象,即重写Comparator接口的Compare()方法。
如果两样都被实现,优先使用比较器的比较规则。
ps: 具体代码实现,详见3.2.2
2.Set集合的两个问题
2.1 Set集合添加的元素如何去重合?
- 对于有值特性(String,Integer,int)的,直接判断进行去重复。
- 对于引用数据类型的类对象:
- hashCode
- equals
首先Set集合会让两两对象,先调用自己的hashCode()方法,判断两个对象的哈希值是否相同;如果相同,再用equals()方法判断内容是否相同。
如果哈希值不同,则无需判断内容是否相同。
2.2 Set集合无序的原因
Set集合添加元素无序是因为其底层用哈希表存储元素:
JDK1.8之前,哈希表 = 数组 + 链表 + (哈希算法)
JDK1.8之后,哈希表 = 数组 + 链表 + 红黑树 +(哈希算法)
哈希算法:
- 先获取元素对象的哈希值
- 用哈希值对底层数组的长度取余
- 取余的结果作为该元素在底层数组的索引位置
- 存入该元素对象
ps:如果索引位置相同,在该数组的位置形成链,依次连接。
用哈希表存储元素,增删改查性能好,但它无序,不重复。
同时考虑到链表可能过长影响性能,在JDK1.8之后,当链表长度超过8时,链表会 转成红黑树 。
ps:LinkedHashSet在底层依然是用哈希表存储元素,
但是每个元素额外带一个链来维护添加顺序,顺着这条链,有序查找输出元素。
3. 代码示例
3.1 用HashSet存储自定义对象
规定:如果学生类的姓名和年龄一样,则视为同一个对象。
分析:即使Student对象内的姓名和年龄完全相同,因为哈希值是根据对象地址得出的,所以把数值完全相同的对象往HashSet集合存储时,都会被存进去。但是现在规定姓名和年龄一样,则视为同一个对象,也就是存进去时前一个要被去掉。‘
所以:
通过重写hashCode()方法和equals()方法可实现规定内容。
做法:重写方法时,让哈希值根据name和age得出;如果哈希值相同,重写后的equals方法判断name和age的值是否相同,若相同,则该对象不会进入HashSet。
import java.util.HashSet;
import java.util.Iterator;
class Student {
private String name;
private int age;
Student() {
}
Student(String name, int age) {
this.name = name;
this.age = age;
}
@Override
public int hashCode() {
return name.hashCode()+age;
}
@Override
public boolean equals(Object obj) {
Student s = (Student)obj;
return this.name.equals(s.name) && this.age==s.age;
}
public int getAge() {
return age;
}
public String getName() {
return name;
}
}
public class HashCodeDemo {
public static void main(String[] args) {
HashSet hashSet = new HashSet();
hashSet.add(new Student("abc1",21));
hashSet.add(new Student("abc2",22));
hashSet