Set接口
Set常用方法
Set接口继承与Collection接口,在父类接口的基础上没有任何的方法拓展,几乎都是之前父类接口的方法,任何集合中只能存储引用类型的数据
- add(E e) 向集合中添加一个新的元素,当没有具体的类型的时候默认为Object类型
说明:- size()返回集合中的元素个数;
- remove(Object o)从集合中删除指定元素,但是只能删除一个,要删除多个,就需要进行迭代(放在循环里删除),正确的调用方法
- addAll(Collection collection);将一个集合中的所有元素添加到另一个集合中(批量的添加)
- clear();清空集合中所有的元素
- contains(Object o);查询集合中是否有o这个对象,在原码中是用
- equals()方法进行判断
- isEmpty();判断当前集合是否为空
- toArray();将当前集合转换为数组
- iterator():获取迭代器
Set接口特点
Set接口的特点:无序不可重复
无序:添加的顺序和迭代的顺序可能不一致,无序不代表随机,元素没有对应的下标
不可重复:每个元素都是互不相等
Set接口常用实现类
HashSet实现类
1. HashSet实现类数据结构分析
在HashSet集合中底层是通过HashMap集合来实现的
在HashMap中数据结构 = 数组 + 链表 + 红黑树
//HashSet构造器
public HashSet() {
map = new HashMap<>();
}
2. HashSet集合添加删除元素的过程
- HashSet类在添加元素的过程中实际上是调用了HashMap类中的
put方法map.put(e, PRESENT),- 在HashMap类(双列接口)中,传入键key对象e和值value对象PRESENT,在HashSet类中PRESENT是一个属性指向了一个没有内容的对象,所以在HashSet中值value是没有意义的,
- 所以在添加元素的时候,需要调用所添加元素的hashCode()方法计算出哈希码,
然后通过哈希算法计算此元素所需要存入的哈希表的桶位所对应的链表,如果此链表为空,那么将存在第一个位置,如果不为空,然后调用所添加元素的equals()方法,判断此链表中是否有相同的元素,如果有就放弃添加,如果没有就存储在链表的尾部。
- 删除元素:删除是通过remove()方法实现的,将一个元素传入remove()方法的时候,会调用该元素的hashCode方法,计算出哈希码,然后根据哈希算法计算出桶位,然后在桶位上面通过equals方法检索链表,找到了就直接删除返回true,没有就返回false
- 然后在HashSet类添加元素之后,在输出相应元素的时所输出的顺序是按照桶位的顺序,然后依次输出桶口对应的链表。
所以即使先添加的元素,到后面也不一定存在前面
放入集合中的元素一定要同时重写hashCode()和equals()方法
3. LinkedHashSet实现类
LinkedHashSet是HashSet的一个子类,可以保证访问的顺序和添加的顺序的一致,但是我们不能因为这个功能将LinkedHashSet理解为有序,因为它在哈希表中储存的位置还是无序,只不过通过一个指针将存入顺序记录了下来,才能让存取和访问的顺序一致。
TreeSet实现类
数据结构
TreeSet就是一个TreeMap,TreeMap底层采用的数据结构是二叉树
注意事项
存入TreeSet中的元素必须具有大小的比较的能力,否则在运行期抛出异常,如果存入的元素为四类八种的包装类,或者String的话,这几种类型包含CompareTo()方法,能够具有比较的能力。
但是如果是其他的引用数据类型,那么就需要在类中继承Comparable接口,重写CompareTo()方法,让引用数据类型具有比较能力。
或者在TreeSet构造方法中传入一个比较器Comparator接口的实现类,该方式可以通过匿名内部类法方式传入。如:
Set<Student> set=new TreeSet<>(new Comparator<Student>() {
public int compare(Student o1, Student o2) {
return o1.getAge()-o2.getAge();
}
});