0
点赞
收藏
分享

微信扫一扫

P519set接口实现类HashSetP520扩容P521源码P523Set底层机制P525set接口实现类P527LinkedHashSetP529set接口实现类P530Map接口的特点P533M

梦幻之云 2022-01-23 阅读 42

P519set接口实现类HashSet

public class HashSetStructure {
    public static void main(String[] args) {
        //模拟一个HashSet的底层(HashMap的底层)
        //1.创建1个数组,数组的类型是Node[]
        //2.有些人直接把Node数组成为表
        Node[] table =new Node[16];
        System.out.println("table="+table);
        //3.创建结点
        Node john = new Node("john2",null);
        table[2]=john;
        Node jack=new Node("jack3",null);
        john.next=jack;//将jack挂点挂载到john
        Node rose = new Node("Rose4", null);
        Node lucy = new Node("lucy5", null);
        table[3]=lucy;//把lucy放到table表的索引
        jack.next=rose;//将rose结点挂载到jack
        System.out.println("table="+table);
    }
}
class Node {//结点存储数据,可以指向下一个,从而形成链表
    Object item;//存放数据
    Node next;//指向下一个结点
    public Node(Object item, Node next) {
        this.item = item;
        this.next = next;
    }
}

P520HashSet扩容机制

P521HashSet源码解读

public class HashSetSource {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add("java");//到此位置,第1 次add 分析完毕.
        hashSet.add("php");//到此位置,第2 次add 分析完毕
        hashSet.add("java");
        System.out.println("set=" + hashSet);//输出set=[java, php]
        /*
        对HashSet的解读数码解读
        1. 执行HashSet()
            public HashSet() {
            map = new HashMap<>();
            }
        2. 执行add()
        public boolean add(E e) {//e = "java"
        return map.put(e, PRESENT)==null;//(static) PRESENT = new Object();
        }
        3.执行put() , 该方法会执行hash(key) 得到key对应的hash值,算法h = key.hashCode()) ^ (h >>> 16)
        public V put(K key, V value) {//key = "java" value = PRESENT 共享
        return putVal(hash(key), key, value, false, true);
        }
        4.执行putVal
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
        boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i; //定义了辅助变量
            //table 就是HashMap 的一个数组,类型是Node[]
            //if 语句表示如果当前table 是null, 或者大小=0
            //就是第一次扩容,到16 个空间.
            if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;
            //(1)根据key,得到hash 去计算该key 应该存放到table 表的哪个索引位置
            //并把这个位置的对象,赋给p
            //(2)判断p 是否为null
            //(2.1) 如果p 为null, 表示还没有存放元素, 就创建一个Node (key="java",value=PRESENT)
            //(2.2) 就放在该位置tab[i] = newNode(hash, key, value, null)
            if ((p = tab[i = (n - 1) & hash]) == null)
            tab[i] = newNode(hash, key, value, null);
            else {
        //追第二次add部分
            //一个开发技巧提示: 在需要局部变量(辅助变量)时候,在创建
            Node<K,V> e; K k; //
            //如果当前索引位置对应的链表的第一个元素和准备添加的key 的hash 值一样
            //并且满足下面两个条件之一:
            //(1) 准备加入的key 和p 指向的Node 结点的key 是同一个对象
            //(2) p 指向的Node 结点的key 的equals() 和准备加入的key 比较后相同
            //就不能加入
​
            if (p.hash == hash &&
            ((k = p.key) == key || (key != null && key.equals(k))))//判断对象、内容相同
            e = p;
​
            //再判断p 是不是一颗红黑树,
            //如果是一颗红黑树,就调用putTreeVal , 来进行添加
            else if (p instanceof TreeNode)
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
​
            else {//如果table 对应索引位置,已经是一个链表, 就使用for 循环比较
            //(1) 依次和该链表的每一个元素比较后,都不相同, 则加入到该链表的最后
            // 注意在把元素添加到链表后,立即判断该链表是否已经达到8 个结点
            // , 就调用treeifyBin() 对当前这个链表进行树化(转成红黑树)
            // 注意,在转成红黑树时,要进行判断, 判断条件
            // if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY(64))
            // resize();
            // 如果上面条件成立,先table 扩容.
            // 只有上面条件不成立时,才进行转成红黑树
            //(2) 依次和该链表的每一个元素比较过程中,如果有相同情况,就直接break
​
            for (int binCount = 0; ; ++binCount) {
            if ((e = p.next) == null) {
            p.next = newNode(hash, key, value, null);
            if (binCount >= TREEIFY_THRESHOLD(8) - 1) // -1 for 1st
            treeifyBin(tab, hash);
            break;
            }
            if (e.hash == hash &&
​
            ((k = e.key) == key || (key != null && key.equals(k))))
            break;
            p = e;
            }
            }
            if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
            e.value = value;
            afterNodeAccess(e);
            return oldValue;
            }
            }
            ++modCount;
            //size 就是我们每加入一个结点Node(k,v,h,next), size++
            if (++size > threshold)
            resize();//扩容
            afterNodeInsertion(evict);
            return null;
            }
         */
    }
}

P523JavaSet底层机制说明,分析HashSet的扩容和转成红黑树机制

public class HashSetSource {
    public static void main(String[] args) {
        /*
        HashSet 底层是HashMap, 第一次添加时,table 数组扩容到16,
        临界值(threshold)是16*加载因子(loadFactor)是0.75 = 12
        如果table 数组使用到了临界值12,就会扩容到16 * 2 = 32,
        新的临界值就是32*0.75 = 24, 依次类推
         */
        HashSet hashSet = new HashSet();
        /*
        for (int i = 0; i < 100; i++) {
            hashSet.add(i);
        }
        在Java8 中, 如果一条链表的元素个数到达TREEIFY_THRESHOLD(默认是8 ),
        并且table 的大小>= MIN_TREEIFY_CAPACITY(默认64),就会进行树化(红黑树),
        否则仍然采用数组扩容机制
         */
        for (int i = 1; i <=7 ; i++) {//在table 的某一条链表上添加了7 个A 对象
            hashSet.add(new A(i));
        }
        /*
        当我们向hashset 增加一个元素,-> Node -> 加入table , 就算是增加了一个size++
​
         */
        for (int i = 1; i <=7 ; i++) {//在table 的另一条链表上添加了7 个B 对象
            hashSet.add(new B(i));
        }
​
​
        System.out.println(hashSet);
    }
}
class B{
    private int n;
​
    public B(int n) {
        this.n = n;
    }
    @Override
    public int hashCode(){
        return 50;
    }
}
​
class A{
    private int n;
​
    public A(int n) {
        this.n = n;
    }
    @Override
    public int hashCode(){
        return 100;
    }
}

P525set接口实现类

public class HashSetE1 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new E("y1",1));
        hashSet.add(new E("y2",2));
        hashSet.add(new E("y1",1));
        System.out.println(hashSet);
​
    }
}
class E{
    private String name;
    private int age;
​
    public E(String name, int age) {
        this.name = name;
        this.age = age;
    }
​
    @Override
    public String toString() {
        return "E{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public boolean equals(Object o) {//如果name 和age 值相同,则返回相同的equals
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        E e = (E) o;
        return age == e.age &&
                Objects.equals(name, e.name);
    }
    @Override
    public int hashCode() //如果name 和age 值相同,则返回相同的hash 值
        return Objects.hash(name, age);
    }
}
public class HSE2 {
    public static void main(String[] args) {
        HashSet hashSet = new HashSet();
        hashSet.add(new Em("y1",111,new MyDate(21,1,1)));
        hashSet.add(new Em("y1",111,new MyDate(21,2,1)));
        hashSet.add(new Em("y1",111,new MyDate(21,1,1)));
        System.out.println(hashSet);
​
    }
}
class Em{
    private String name;
    private double sal;
    private MyDate birthday;
​
    public Em(String name, double sal, MyDate birthday) {
        this.name = name;
        this.sal = sal;
        this.birthday = birthday;
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Em em = (Em) o;
        return Objects.equals(name, em.name) &&
                Objects.equals(birthday, em.birthday);
    }
​
    @Override
    public int hashCode() {
        return Objects.hash(name, birthday);
    }
​
    @Override
    public String toString() {
        return "Em{" +
                "name='" + name + '\'' +
                ", sal=" + sal +
                ", birthday=" + birthday +
                '}';
    }
}
class MyDate{
    private int year;
    private int moth;
    private int day;
​
    public MyDate(int year, int moth, int day) {
        this.year = year;
        this.moth = moth;
        this.day = day;
    }
​
    @Override
    public String toString() {
        return "MyDate{" +
                "year=" + year +
                ", moth=" + moth +
                ", day=" + day +
                '}';
    }
​
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        MyDate myDate = (MyDate) o;
        return year == myDate.year &&
                moth == myDate.moth &&
                day == myDate.day;
    }
​
    @Override
    public int hashCode() {
        return Objects.hash(year, moth, day);
    }
}

P527LinkedHashSet

public class LinkedHashSetSource {
    public static void main(String[] args) {
        Set set = new LinkedHashSet();
        set.add(new String("A"));
        set.add(456);
        set.add(456);
        set.add(new Customer("liu",1001));
        set.add(123);
        set.add("HSP");
        System.out.println(set);//输出[A, 456, New.Customer@10f87f48, 123, HSP]
        //1.linkedHHashSet加入顺序和取出元素的顺序
        //2.linkedHHashSet底层维护的是一个linkedHHashMap(是HashMap的子类)
        //3.LinkedHashSet底层结构i(数组table和双向链表)
        //4.添加第一次的时候,直接将数组Table扩容到16,存放的结点类型是LinkedHashMap$Entry
        //5.数组是HashMap$Node[]存放的元素/数据是LinkedHashMap$Entry类型
    }
}
class Customer{
    private String name;
    private int no;
​
    public Customer(String name, int no) {
        this.name = name;
        this.no = no;
    }
}

P529set接口实现类

public class LinkedHashSetE {
    public static void main(String[] args) {
        LinkedHashSet lkht = new LinkedHashSet();
        lkht.add(new Car("1a",1));
        lkht.add(new Car("1B",2));
        lkht.add(new Car("1c",3));
        lkht.add(new Car("1d",4));
        lkht.add(new Car("1c",5));
        lkht.add(new Car("1B",2));
        System.out.println(lkht);
    }
}
class Car{
    private String name;
    private double price;
​
    public Car(String name, double price) {
        this.name = name;
        this.price = price;
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Car car = (Car) o;
        return Double.compare(car.price, price) == 0 &&
                Objects.equals(name, car.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, price);
    }
    @Override
    public String toString() {
        return "\nCar{" +
                "name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

P530Map接口的特点

public class Map_ {
    public static void main(String[] args) {
​
        //老韩解读Map 接口实现类的特点, 使用实现类HashMap
        // 1. Map 与Collection 并列存在。用于保存具有映射关系的数据:Key-Value(双列元素)
        // 2. Map 中的key 和value 可以是任何引用类型的数据,会封装到HashMap$Node 对象中
        // 3. Map 中的key 不允许重复,原因和HashSet 一样,前面分析过源码.
        // 4. Map 中的value 可以重复
        // 5. Map 的key 可以为null, value 也可以为null ,
        // 注意key 为null,只能有一个,value 为null ,可以多个
        //6. 常用String 类作为Map 的key
        //7. key 和value 之间存在单向一对一关系,即通过指定的key 总能找到对应的value
       Map map = new HashMap();
       map.put("n1","1y");
       map.put("n2","2y");
       map.put("n1","3y");//输入{n1=3y, n2=2y},当有相同的K,就相当于替换
        map.put("n3","3y");//输出{n1=3y, n2=2y, n3=3y}
        //3.4.5
        map.put(null,null);//{null=null, n1=3y, n2=2y, n3=3y}
        map.put(null,"abc");//{null=abc, n1=3y, n2=2y, n3=3y},替换
        map.put("n4",null);//{null=abc, n1=3y, n2=2y, n3=3y, n4=null}
        //6
        map.put(1,"m1");//{null=abc, 1=m1, n1=3y, n2=2y, n3=3y, n4=null}
        System.out.println(map);//输出{n1=1y, n2=2y}
        //7. 通过get 方法,传入key ,会返回对应的value
        System.out.println(map.get("n1"));//输出3y
    }
}

P531Map接口的特点2

public class MapSource {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("no1", "韩顺平");//k-v
        map.put("no2", "张无忌");//k-v
        //1.k-v最后是HashMap$Node node=newNode(hash,key,value,null)
        //2.k-v为了程序员的遍历,还会创建EntrySet集合,该集合存放的元素的类型是Entry
        //而一个Entry对象就有k,v EntrySet<Entry<k,v>,
        // 即为transient Set<Map.Entry<K,V>> entrySet;
        //3.entrySet中,定义类型是Map.Entry,但是实际上存放的还是HashMap$Node
        //这个是因为HashMap$Node implement Map.Entry
        //4.当把HashMap$Node 对象存放到entrySet就方便我们遍历,因为Map.entry提供了重要的方法
        //一个是getValue,一个是getkey();
​
        Set set=map.entrySet();
        System.out.println(set.getClass());//输出class java.util.HashMap$EntrySe
        for (Object oBJ :set) {
            System.out.println(oBJ.getClass());
            //输出class java.util.HashMap$Node class java.util.HashMap$Node
            //为了从 HashMap$Node中取出K-V
            //先进行一个向下转型
            Map.Entry entry=(Map.Entry)  oBJ;
            System.out.println(entry.getKey()+"\t"+entry.getValue());
            //输出  no2  张无忌     no1    韩顺平
        }
         Set set1=map.keySet();
        System.out.println(set1.getClass());
        Collection values = map.values();
        System.out.println(values.getClass());
        //输出class java.util.HashMap$KeySet,
        // class java.util.HashMap$Value
    }
}

P532Map接口方法

public class MapMethod {
    public static void main(String[] args) {
        //演示map 接口常用方法
        //1.添加
        Map map = new HashMap();
        map.put("邓超", new Book("",100));//OK
        map.put("邓超", "孙俪");//替换-> 一会分析源码
        map.put("王宝强", "马蓉");//OK
        map.put("宋喆", "马蓉");//OK
        map.put("刘令博", null);//OK
        map.put(null, "刘亦菲");//OK
        map.put("gj", "gjl");//OK
        map.put("hsp", "hsp 的老婆");
        System.out.println("map=" + map);
        // remove:根据键删除映射关系
        map.remove(null);
        System.out.println("map=" + map);//此时输出null=刘亦菲没有了
        // get:根据键获取值
        Object val = map.get("gj");
        System.out.println("val=" + val);//输出val=gjl
        // size:获取元素个数
        System.out.println("k-v=" + map.size());//目前有6个
        // isEmpty:判断个数是否为0
        System.out.println(map.isEmpty());//F
        // clear:清除k-v
        // map.clear();
        System.out.println("map=" + map);//输出{}
        // containsKey:查找键是否存在
        System.out.println("结果=" + map.containsKey("hsp"));//T
    }
}
class Book{
    private String name;
    private int num;
    public Book(String name, int num) {
        this.name = name;
        this.num = num;
    }
}

P533Map的六种遍历方式

public class MapMethod {
    public static void main(String[] args) {
        Map map = new HashMap();
        map.put("邓超", "1孙俪");//替换-> 一会分析源码
        map.put("王宝强", "2马蓉");//OK
        map.put("宋喆", "3马蓉");//OK
        map.put("刘令博", null);//OK
        map.put(null, "5刘亦菲");//OK
        map.put("gj", "6gjl");//OK
        map.put("hsp", "7hsp 的老婆");
        System.out.println("map=" + map);
        //第一组: 先取出所有的Key , 通过Key 取出对应的Value
​
        Set keySet = map.keySet();
        Iterator iterator = keySet.iterator();
        while (iterator.hasNext()) {
            Object next =  iterator.next();
            System.out.println(map.get(next));
        }
        for (Object key :keySet) {
            System.out.println(map.get(key));
            //输出1孙俪//3马蓉//null//5刘亦菲//6gjl//7hsp 的老婆
        }
        //第二组取出所有的values
        Collection values = map.values();
        //这里可以使用所有的collection遍历方式,增强for,iterator,
​
        //第三组通过entrySet来取出k-v,将Node做成Entry放入Set中
        Set entrySet = map.entrySet();
        for (Object entry :entrySet) {
            //将entry转成Map.Entry
         Map.Entry m = (Map.Entry) entry;
         //m提供了两个方法,getkey和getvalue
            System.out.println(m.getKey()+"-"+m.getValue());
            //输出邓超-1孙俪//宋喆-3马蓉//刘令博-null//null-5刘亦菲
            // gj-6gjl//hsp-7hsp 的老婆//王宝强-2马蓉
        }
        //迭代器
        Iterator iterator3 = entrySet.iterator();
        while (iterator3.hasNext()) {
            Object entry = iterator3.next();
            //System.out.println(next.getClass());
            // HashMap$Node -实现-> Map.Entry (getKey,getValue)
            // 向下转型Map.Entry
            Map.Entry m = (Map.Entry) entry;
            System.out.println(m.getKey() + "-" + m.getValue());
        }
    }
}

P535课堂练习

public class MapE1 {
    public static void main(String[] args) {
        Map hashMap = new HashMap();
        hashMap.put(1,new EM(1,111));
        hashMap.put(2,new EM(2,112));
        hashMap.put(3,new EM(3,113));
        for (Object key : hashMap.keySet()) {
        EM em  = (EM) hashMap.get(key);
            if(em.getSal()>112) {
                System.out.println(em);
                //EM{id=3, sal=113.0}
            }
        }
        //迭代器
        Set entryset = hashMap.entrySet();
        Iterator iterator = entryset.iterator();
        while (iterator.hasNext()) {
            //Object next =  iterator.next();//拿出的是Mapentry
            Map.Entry entry = (Map.Entry) iterator.next();
            //entry的运行类型是hashmap$Node
            //通过entry取得getkey和getvalue\
            EM em1 = (EM) entry.getValue();
            if (em1.getSal() > 112) {
                System.out.println(em1);
                //EM{id=3, sal=113.0}
            }
        }
    }
}
class EM{
    private int id;
    private double sal;
​
    public EM(int id, double sal) {
        this.id = id;
        this.sal = sal;
    }
​
    @Override
    public String toString() {
        return "EM{" +
                "id=" + id +
                ", sal=" + sal +
                '}';
    }
​
    public int getId() {
        return id;
    }
​
    public void setId(int id) {
        this.id = id;
    }
​
    public double getSal() {
        return sal;
    }
​
    public void setSal(double sal) {
        this.sal = sal;
    }
}

P536HMap底层机构

P537HMap的底层机制及源码剖析

public class HashMapSource1 {
    public static void main(String[] args) {
        HashMap map = new HashMap<>();
        map.put("java", 10);//ok
        map.put("php", 10);//ok
        map.put("java", 20);//替换value,此时
        System.out.println("map=" + map);//
        /*老韩解读HashMap 的源码+图解
        1. 执行构造器new HashMap()
         初始化加载因子loadfactor = 0.75
        HashMap$Node[] table = null
        2. 执行put 调用hash 方法,计算key 的hash 值(h = key.hashCode()) ^ (h >>> 16)
            public V put(K key, V value) {//K = "java" value = 10
            // return putVal(hash(key), key, value, false, true);
        3.执行putVal
        源码如下:
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                   boolean evict) {
        Node<K,V>[] tab; Node<K,V> p; int n, i;//辅助变量
        //如果底层的table 数组为null, 或者length =0 , 就扩容到16
        if ((tab = table) == null || (n = tab.length) == 0)
            n = (tab = resize()).length;//此时table为16,全为null
            //取出hash 值对应的table 的索引位置的Node, 如果为null, 就直接把加入的k-v
            //, 创建成一个Node ,加入该位置即可
        if ((p = tab[i = (n - 1) & hash]) == null)//根据hash确定索引位置有无元素,若无
            tab[i] = newNode(hash, key, value, null);
            //执行完此句之后,table有一个元素,
        else {
            Node<K,V> e; K k;//辅助变量
            // 如果table 的索引位置的key 的hash 相同和新的key 的hash 值相同,
            // 并满足(table 现有的结点的key 和准备添加的key 是同一个对象|| equals 返回真)
            // 就认为不能加入新的k-v
            if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
                e = p;
            else if (p instanceof TreeNode)//如果当前的table 的已有的Node 是红黑树,就按照红黑树的方式处
                e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
            else {//这个后面就是链表
            //如果找到的结点,后面是链表,就循环比较
                for (int binCount = 0; ; ++binCount) {//死循环
                    if ((e = p.next) == null) {//如果整个链表,没有和他相同,就加到该链表的最后
                    //加入后,判断当前链表的个数,是否已经到8 个,到8 个,后
​
                        p.next = newNode(hash, key, value, null);
                        if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        //T-T=8
                            treeifyBin(tab, hash);//就调用treeifyBin 方法进行红黑树的转换
                        break;
                    }
                    if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                        break;//如果在循环比较过程中,发现有相同,就break,就只是替换value
                    p = e;
                }
            }
            if (e != null) { // existing mapping for key
                V oldValue = e.value;
                if (!onlyIfAbsent || oldValue == null)
                    e.value = value;//值已经被替换了
                afterNodeAccess(e);
                return oldValue;
            }
        }
        ++modCount;//每增加一个Node ,就size++
        if (++size > threshold)//threshold=12,其实到达12就扩容,12是第一次,其实是临界值
            resize();
        afterNodeInsertion(evict);
        return null;
    }
    源码:resize()
    final Node<K,V>[] resize() {
        Node<K,V>[] oldTab = table;
        int oldCap = (oldTab == null) ? 0 : oldTab.length;
        int oldThr = threshold;
        int newCap, newThr = 0;
        if (oldCap > 0) {
            if (oldCap >= MAXIMUM_CAPACITY) {
                threshold = Integer.MAX_VALUE;
                return oldTab;
            }
            else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                     oldCap >= DEFAULT_INITIAL_CAPACITY)
                newThr = oldThr << 1; // double threshold
        }
        else if (oldThr > 0) // initial capacity was placed in threshold
            newCap = oldThr;
        else {               // zero initial threshold signifies using defaults
            newCap = DEFAULT_INITIAL_CAPACITY;//实际上D-I-C=16,D-L-I=0.75
            newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
        }
        if (newThr == 0) {
            float ft = (float)newCap * loadFactor;
            newThr = (newCap < MAXIMUM_CAPACITY && ft < (float)MAXIMUM_CAPACITY ?
                      (int)ft : Integer.MAX_VALUE);
        }
        threshold = newThr;
        @SuppressWarnings({"rawtypes","unchecked"})
        Node<K,V>[] newTab = (Node<K,V>[])new Node[newCap];
        table = newTab;
        if (oldTab != null) {
            for (int j = 0; j < oldCap; ++j) {
                Node<K,V> e;
                if ((e = oldTab[j]) != null) {
                    oldTab[j] = null;
                    if (e.next == null)
                        newTab[e.hash & (newCap - 1)] = e;
                    else if (e instanceof TreeNode)
                        ((TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                    else { // preserve order
                        Node<K,V> loHead = null, loTail = null;
                        Node<K,V> hiHead = null, hiTail = null;
                        Node<K,V> next;
                        do {
                            next = e.next;
                            if ((e.hash & oldCap) == 0) {
                                if (loTail == null)
                                    loHead = e;
                                else
                                    loTail.next = e;
                                loTail = e;
                            }
                            else {
                                if (hiTail == null)
                                    hiHead = e;
                                else
                                    hiTail.next = e;
                                hiTail = e;
                            }
                        } while ((e = next) != null);
                        if (loTail != null) {
                            loTail.next = null;
                            newTab[j] = loHead;
                        }
                        if (hiTail != null) {
                            hiTail.next = null;
                            newTab[j + oldCap] = hiHead;
                        }
                    }
                }
            }
        }
        return newTab;
    }
    源码:treeifyBin
    5. 关于树化(转成红黑树)
    //如果table 为null ,或者大小还没有到64,暂时不树化,而是进行扩容.
    //否则才会真正的树化-> 剪枝
    final void treeifyBin(Node<K,V>[] tab, int hash) {
        int n, index; Node<K,V> e;
        if (tab == null || (n = tab.length) < MIN_TREEIFY_CAPACITY)//注意M_T_C=64
            resize();
        else if ((e = tab[index = (n - 1) & hash]) != null) {
            TreeNode<K,V> hd = null, tl = null;
            do {
                TreeNode<K,V> p = replacementTreeNode(e, null);
                if (tl == null)
                    hd = p;
                else {
                    p.prev = tl;
                    tl.next = p;
                }
                tl = p;
            } while ((e = e.next) != null);
            if ((tab[index] = hd) != null)
                hd.treeify(tab);
        }
    }
            */
​
    }
}

P538HMap扩容树化触发

public class HashMapSource2 {
    public static void main(String[] args) {
        HashMap hashMap = new HashMap();
        for (int i = 1; i <=12; i++) {
            hashMap.put(new A(i),"hello");
        }
        hashMap.put("aaa","bb");
        //当8的时候不树话,9扩容32,10的时候扩容64,加入11进行treeNode
        System.out.println(hashMap);
        //布置一个任务,自己设计代码去验证,table 的扩容
        // 0 -> 16(12) -> 32(24) -> 64(64*0.75=48)-> 128 (96) ->
        // 自己设计程序,验证-》增强自己阅读源码能力. 看别人代码.
​
    }
}
class A{
    private int num;
​
    public A(int num) {
        this.num = num;
    }
    @Override//所以对象的hashcode都一样
    public int hashCode() {
        return 100;
    }
    @Override
    public String toString() {
        return "\nA{" +
                "num=" + num +
                '}';
    }
}
举报

相关推荐

Map接口实现类——HashTable的介绍

0 条评论