HashSet的方法:继承自Set 或者说Collection(与List不同的是 List中新增了许多关于index的方法) HashSet的特点:无序 无重复 无索引 无序是指元素取出时的顺序与添加时的顺序不一致 但取出的顺序是固定的(顺序取决于元素hash后的结果) 无重复是指无法在集合中存放重复的元素 无索引是指无法通过索引获取或操作集合中的元素 HashSet的底层:HashMap 而HashMap的底层是 数组 + 单向链表(提高存取效率) + 红黑树(在链表达到一定长度之后会被替换为红黑树 红黑树可以提高检索效率) HashSet添加元素的过程: 01.获取元素的hash值 并将其转换为索引值 02.查看table(HashMap内部维护的一个Node数组)对应索引位置是否已添加元素 若未添加则直接添加 反之则调用equals方法进行判断(若该索引处存储了多个元素 则需要由头结点至尾结点逐一判断) 若存在相同元素则放弃添加 反之则添加至链表尾端 03.在Java8中 添加元素时 若该链表的长度>=TREEIFY_THRESHOLD(默认为8) 并且table.length>=MIN_TREEIFY_CAPACITY(默认为64)时 该链表就会进行树化(红黑树) 注:添加元素时若该链表的长度>=TREEIFY_THRESHOLD 则会开始树化 即添加第九个元素时 链表会开始树化
无序与无重复:
- public class HashSetSource {
- public static void main(String[] args) {
- Set
-
- //不允许添加重复元素
- set.add("jerry");
- set.add("tom");
- set.add(null);
- set.add("jerry");
- set.add("tom");
- set.add(null);
- System.out.println(set);
-
- //加深理解
- set.add(new Cat("cat"));
- set.add(new Cat("cat"));
- System.out.println(set);
-
- //再次加深理解
- //不能被一同放入的原因是String类的equals方法与hashCode方法均被重写
- set.add(new String("spike"));
- set.add(new String("spike"));
- System.out.println(set);
- }
- }
-
- class Cat{
- String name;
-
- public Cat(String name) {
- this.name = name;
- }
-
- @Override
- public String toString() {
- return "Cat{" +
- "name='" + name + '\'' +
- '}';
- }
- }
无索引:方法均与索引无关,即无法通过索引获取或操作集合中的元素
- //模拟HashSet(HashMap)的底层结构:数组 + 链表
- public class HashSetStructure {
-
- public static void main(String[] args) {
- //创建结点数组 结点数组常被称为"表"
- Node[] table = new Node[8];
-
- //创建结点
- Node node01 = new Node("ONE", null);
- Node node02 = new Node("TWO", null);
- Node node03 = new Node("THREE", null);
-
- //链接结点
- table[0] = node01;
- node01.next = node02;
- node02.next = node03;
-
- //输出链表
- System.out.println(table[0]);
- }
-
- }
-
- class Node{
- Object item;
- Node next;
-
- public Node(Object item, Node next) {
- this.item = item;
- this.next = next;
- }
-
- @Override
- public String toString() {
- return "Node{" +
- "item=" + item +
- ", next=" + next +
- '}';
- }
- }
若觉得输出结果不够直观,可以参考Debug图