ArrayList和HashMap的My笔记

1.1ArrayList

接口实现ArreyList集合实现了RandomAccess(随机访问)接口不适合使用迭代器来进行遍历,

重写了序列化方法,transient Object[] elementDate(存储数据的节点) 节省了50%的序列化空间

近似1.5倍扩容  时间复杂度为o1

 

 

 

初始长度为10会进行1次扩容

 

System.arreyCopy();进行浅拷贝扩容模式

System.arraycopy()方法详解 system.arraycopy(详解)

 JAVA基础----java泛型中E,T,?的区别(泛型详解)

一、深度复制和浅度复制的区别

         Java数组的复制操作可以分为深度复制和浅度复制,简单来说深度复制,可以将对象的值和对象的内容复制;浅复制是指对对象引用的复制。(浅拷贝扩容一个框用原来数据内存地址指向框,深拷贝重新创建一个数据并将数据拷贝到新数组当中)

1.1使用java为我们提供的工具类进行生产ArrayList

这样不行(否)

1.1第一种

使用Arrays.saList();进行创建list集合

自己创建了一个私有的ArrayList底层是继承了AbstractList,没有重写add方法,而父类AbstractList的add方法会直接抛出异常

抛出异常改为:UnsupportedOperationException

 

在什么情况下使用Arrays.saList();呢?

元素个数固定使用

在 不可做删除 不可做增加,可以做修改和查询的情况下使用

王校长总结:

 

1.2第二种

 

数组里面元素是对象所以需要赋值为null值,赋为null值之后对象为不可达对象会被GC回收掉,防止内存的泄露问题

1.2 Clear()

多实用clear方法进行清除操作完成空间的复用,每次clear()只会将数据内容清空掉,不会清空list原有的扩容长度

 

 

认为利用了addAll();里面的边缘性返回值,导致了非异常-异常

如果list为null那么‘’;

就会抛出异常(在生产环境不能抛出异常这样)

问题在于:返回值有歧义

 

1.3ArrayList序列化问题

集合当中元素存放在被transient修饰的Object[]当中,元素不会被序列化

 

HashMap

put方法的hash计算

hashCode右移16位异或自身

 

1.1 comparableClassFor()

ParameterizedType代表类似ArrayList<String>  包裹类型判断

 

 

奇妙算法2n次方的向上

 

1.2 get()方法

右移16位异或自身

getNode();方法 判断当中加上Hash计较,是为了加快运算效率,hash是int类型的

 

//Get方法
public V get(Object key) {
    HashMap.Node<K,V> e;
    return (e = getNode(hash(key), key)) == null ? null : e.value;
}
//get方法
final HashMap.Node<K,V> getNode(int hash, Object key) {
    HashMap.Node<K,V>[] tab; HashMap.Node<K,V> first, e; int n; K k;
    if ((tab = table) != null && (n = tab.length) > 0 &&//判断传入key是否在HashMap当中
            (first = tab[(n - 1) & hash]) != null) {
        if (first.hash == hash && // always check first node
                ((k = first.key) == key || (key != null && key.equals(k))))//数组链表头节点是对应的key,则直接将Value返回
            return first;
        if ((e = first.next) != null) {//如果链表头不为对应数据则进行非空判断
            if (first instanceof HashMap.TreeNode)//判断类型是否为树
                return ((HashMap.TreeNode<K,V>)first).getTreeNode(hash, key);
            do {        //为链表,do while循环取出链表当中的数据
                if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))
                    return e;
            } while ((e = e.next) != null);
        }
    }
    //如果没有返回null值
    return null;
}

1.3 put();

//put元素核心方法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;
    if ((tab = table) == null || (n = tab.length) == 0)//如果数组为空进行设置初始容量
        n = (tab = resize()).length;
    if ((p = tab[i = (n - 1) & hash]) == null)//计算出put元素的hash值与或节点数量判断存储节点是否为null进行存储
        tab[i] = newNode(hash, key, value, null);
    else {
        Node<K,V> e; K k;
        if (p.hash == hash &&
                ((k = p.key) == key || (key != null && key.equals(k))))
            e = p;
        else if (p instanceof HashMap.TreeNode)//判断书否是树结构
            e = ((HashMap.TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {
                if ((e = p.next) == null) {//遍历链表节点进行节点的存储
                    p.next = newNode(hash, key, value, null);
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st
                        treeifyBin(tab, hash);//长度大于8时进行树化处理
                    break;
                }
                if (e.hash == hash &&
                        ((k = e.key) == key || (key != null && key.equals(k))))//数据在链表当中存在直接返回null
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key//key重复进行覆盖操作
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)
                e.value = value;
            afterNodeAccess(e);
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold) //先添加后扩容操作
        resize();
    afterNodeInsertion(evict);
    return null;
}

 

1.4 resize();扩容方法

扩容为底层数组的长度

final HashMap.Node<K,V>[] resize() {
    HashMap.Node<K,V>[] oldTab = table;//old  16 长度
    int oldCap = (oldTab == null) ? 0 : oldTab.length;//16
    int oldThr = threshold;//12
    int newCap, newThr = 0;
    if (oldCap > 0) {
        if (oldCap >= MAXIMUM_CAPACITY) {//超过2的30次方直接不管了
            /**
             * threshold 这个值,只与扩容有关,他的大小不会限制其他操作
             */
            threshold = Integer.MAX_VALUE;//2147483647
            return oldTab;
        }
        /**
         * 将数组扩容2倍
         */
        else if ((newCap = oldCap << 1) < MAXIMUM_CAPACITY &&
                oldCap >= DEFAULT_INITIAL_CAPACITY)
            newThr = oldThr << 1; // double threshold//thr也进行扩容二倍
    }
    else if (oldThr > 0) // initial capacity was placed in threshold
        newCap = oldThr;
    else {               // zero initial threshold signifies using defaults
        newCap = DEFAULT_INITIAL_CAPACITY;
        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;//真正的开始给threhod进行了newThr的赋值
    @SuppressWarnings({"rawtypes","unchecked"})
    HashMap.Node<K,V>[] newTab = (HashMap.Node<K,V>[])new HashMap.Node[newCap];
    table = newTab;//真正的开始给table  进行newTab的赋值


    //=========================开始节点的迁移========================================
    if (oldTab != null) {
        for (int j = 0; j < oldCap; ++j) {
            HashMap.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 HashMap.TreeNode)
                /**
                 * 如果进行map扩容我们的树肯定会被拆掉  性能消耗很大
                 * 实际情况下,我们的HashMap很难达到 红黑树。 Hash 十分散列;我们业务,不可能
                 * 也不能够,不允许 在一个map放那么多元素。
                 * 如果我需要从db里取出2的30次方个元素,需要用hashMap进行处理那么怎么办?
                 * 我们可以使用clear();方法进行清除数据而不会清除扩容空间,这样我们就减少了扩容对性能的损耗
                 * 我们只需要进行分批处理clear();在处理
                 */
                    ((HashMap.TreeNode<K,V>)e).split(this, newTab, j, oldCap);
                else { // preserve order
                    HashMap.Node<K,V> loHead = null,//old 链表的 头节点
                            loTail = null;  //old 链表的尾节点
                    HashMap.Node<K,V> hiHead = null,// new 链表的 投节点
                            hiTail = null;  //new 链表的尾节点
                    HashMap.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 {//如果不等于0.变化位置,将该元素重新方到新的table当中
                            if (hiTail == null)
                                hiHead = e;
                            else
                                hiTail.next = e;
                            hiTail = e;
                        }
                    } while ((e = next) != null);


                    //真正添加
                    if (loTail != null) {
                        loTail.next = null;
                        newTab[j] = loHead; //这是真的将数据放入newTab里面了
                    }
                    if (hiTail != null) {
                        hiTail.next = null;
                        newTab[j + oldCap] = hiHead; //这是真的将数据放入newTab里面了
                    }
                }
            }
        }
    }
    return newTab;
}

//sparkStream大数据处理

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值