Set::是无序的(指的是存入顺序和展示顺序不一样),并且不允许重复
1. HashSet, 集合 无序并且不允许重复
数据结构: 哈希表
jdk 1.7 哈希表是由: 数组+单向链表
1> 当创建hashSet对象以后
先在内存中初始化了一个数组 长度16 , 初始容量16
2> 当向集合中添加元素, 调用add方法的时候
则调用元素的hashcode方法, 根据此对象的内存地址 经过一定的运算 得到一个int类型的 哈希码
3> 将哈希码存储到数组中
具体详细过程:
先将哈希码取余当前数组容量, 余数对应着数组的下标. 这个元素
就会存到数组下标对应的位置.
当此数组的此位置没有元素的时候 , 直接存.
当次数组的此位置有元素的时候, 需要跟此位置所有数据进行对比. 如果发现不同
则, 将此数据放到此下标位置. 将原来的数据, 向下存储到一个链表中(相当于挤下去了)
至此,反复执行此操作, 就出现了 数组+链表的存储结构
如果发现哈希码与数组以及链表中的哈希码,相同, 则近一步调用equals方法帮助判断是否一定相同
如果相同则, 不添加到集合, 如果不同, 则添加到集合
4> 具体如何判断此对象是否是与集合中元素相同?
1> 通过hashcode方法 , 根据内存地址经过指定运算, 得到哈希值.
2> 拿到哈希值, 先去取余当前数组容量, 确定想要存储的位置.
遍历此下标位置以及对应的链接列表中的所有数据进行对比.
如果不同, 则直接存到数组中, 把原来数据 挤到链表中 .
如果相同, 则调用equals方法. 进一步判断. 如果确定相同 则不存储, 如果不同, 则存储
5> 如果想要判断对象的内容是否相同, 如果相同则不添加到集合中
需要在泛型类中 重写hashcode 和equals
6> 哈希表中的数组的扩容?
当数组中有百分之75的位置 已经存储了数据, 则触发扩容.
扩容的容量是 当前容量的一倍
将原来所有的数据重新取余当前数组容量. 重新确定位置
7> jdk 1.8以后
哈希表是 数组+链表+二叉树
当链表中数据超过8个则变成二叉树. 当小于6个的时候变成链表
目的提高遍历查找效率
2. TreeSet 利用树的结构 无序并且不允许重复. 可排序的
根节点: 二叉树中第一个节点
子节点/父节点 : 子节点 相对于父节点来说, 子节点 父节点的分支
左节点/右节点: 根节点左边的分支 左节点 , 右边的分支 右节点
左子树/右子树: 根节点 左边 整个所有的节点, 左子树, 右边所有的节点 右子树
二叉树中 每一个节点 最多只能分出两个分支 .
遍历方式:
前序: 根左右
中序: 左根右
后序: 左右根
根据二叉树可以给集合中数据进行排序
真正来说排序的过程: 1. 需要自然排序或者 定制排序. 确定 位置
2. 根据位置 将数据放到二叉树中
TreeSet<Person>
要求泛型中的类,必须实现自然排序或者定制排序, 否则 会报 ClassCastException
两种方式进行排序
* 自然排序
* 1.先定义泛型类 , 此类实现Comparatable<集合泛型中添加的类>
* 2.重写compareTo
* 具体的比较流程
* 3. 创建TreeSet集合 添加数据
* 定制排序
* 1. 先定义泛型类
* 2. 定义一个比较器的类 , 实现Comparator<集合泛型中类>
* 3. 重写 compare方法
* 4. 创建TreeSet集合.
* 集合的构造方法中, 必须要 传递比较器对象
* 5. 向集合中添加数据
*
排序规则:
升序
* 调用者> 参数 返回 正数
* 调用者 < 参数 负数
* 调用者 = 参数 0
*
* 降序
* 调用者> 参数 负数
* 调用者 < 参数 正数
* 调用者 = 参数 0
3. 所有集合都是引用数据类型
都可以作为属性 参数 返回值
哪个类需要实现 排序, 或者重写equals hascode
泛型中的类需要