1、set接口
(1)特点
- 元素不能重复(equals判断)
- 无序
@Test public void test1() { Set set=new HashSet(); set.add("zhai"); set.add("123"); set.add("null"); set.add("123"); set.add("90"); System.out.println(set); }
[123, null, 90, zhai]
注意:Treeset不允许添加null元素
(2)特有方法
没有特有方法,主要是从collection接口继承来的
(3)遍历方式
和collection接口的遍历方式相同:迭代器、增强for
2、HashSet底层结构
(1)底层结构
- 哈希表
public HashSet() { map = new HashMap<>(); }
因为HashSet维护的是一个HashMap对象,而HashMap维护的是一个哈希表,两者都是基于hash结构的
- 无序:根据哈希值确定元素在哈希表中的位置
(2)去除重复原理
原理:
先获取元素的哈希值,通过一些运算获取一个整数索引index(要存放在数组的位置)
如果索引处没有元素,则直接添加
如果索引处有其他元素,则需要进行equals判断,如果不相等,则以链表的形式追加到已有元素的后面并返回true,如果相等则直接覆盖并返回false
如果不是哈希表的结构,需要进行大量的equals判断,哈希表的使用大大减少了equals的使用
重写equals与hashCode方法(https://www.cnblogs.com/zhai1997/p/11354885.html)
存储已经存在的数据类型的数据,不用重写equals和hashcode方法,即可去除重复元素
存储自定义类型的数据需要重写equals和hashcode方法
3、TreeSet底层结构
(1)底层结构
基于map对象(TreeMap),treeMap的底层是红黑树的结构,可以实现对元素的排序
(2)特点
- 不允许重复
- 可以实现对里面的元素进行排序(自然排序、定制排序)
- 红黑树存储的时候是左边的存较小的元素,右边存储较大的元素,取出的时候可以按顺序取出,先取出20,然后25... ...
- 红黑树与二叉树的不同是,红黑树给二叉树标记了颜色,例如:左边红色右边黑色,当左边的红色元素过多右边黑色元素过少的时候,红黑树就失去了平衡,此时就要重新打乱顺序重新选出根元素,使得两边保持平衡
- 红黑树是二叉树的一种
(3)TreeSet的使用
@Test public void test1() { Set set=new TreeSet(); set.add(new Student("zhai",12)); set.add(new Student("zz",13)); set.add(new Student("zhang",14)); set.add(new Student("liu",19)); set.add(new Student("zhang",14)); for (Object s: set){ System.out.println(s); } }
java.lang.ClassCastException: com.zhb.domain.Student cannot be cast to java.lang.Comparable
报错的类型是类型转换异常,原因是添加元素的时候在确定元素在二叉树中的位置的时候,需要当前元素与结点元素进行比较,小的左,大的右,相等的话不添加,但是对象不具有比较性,因此报错
要让其具有比较性有两种方法:
自然排序:
public class Student implements Comparable{ public String sname; public int age; @Override public String toString() { return "Student{" + "sname='" + sname + '\'' + ", age=" + age + '}'; } public Student(String sname, int age) { this.sname = sname; this.age = age; } public String getSname() { return sname; } public void setSname(String sname) { this.sname = sname; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public int compareTo(Object o) { Student s=(Student)o; return Integer.compare(this.age,s.age); } }
Student{sname='zhai', age=12} Student{sname='zz', age=13} Student{sname='zhang', age=14} Student{sname='liu', age=19}
此方法需要实现接口重写方法
定制排序:
@Test public void test1() { Set set=new TreeSet(new Comparator() { @Override public int compare(Object o1, Object o2) { Student s1=(Student)o1; Student s2=(Student)o2; return Integer.compare(s1.getAge(),s2.getAge()); } }); set.add(new Student("zhai",12)); set.add(new Student("zz",13)); set.add(new Student("zhang",14)); set.add(new Student("liu",19)); set.add(new Student("zhang",14)); for (Object s: set){ System.out.println(s); } }
Student{sname='zhai', age=12} Student{sname='zz', age=13} Student{sname='zhang', age=14} Student{sname='liu', age=19}
在定义TreeSet的同时定义比较器
(4)添加方法原理
底层是treemap的添加:
进行元素的比较:
调用的比较器:
(5)如何实现去重
通过比较方法(compareTo方法)的返回值是否为0来判断元素是否重复