Java集合容器

基本内容:ArrayList、HashMap、HashSet、TreeMap、LinkedHashMap、ConcurrentHashMap

1.ArrayList,支持随机访问,插入删除操作时间复杂度为O(n)。

   (a) 默认初始容量为10:private static final int DEFAULT_CAPACITY = 10;

    (b)扩容时,扩充为原来的1.5倍: int newCapacity = oldCapacity + (oldCapacity >> 1);

    (c)基于数组实现,底层数组用transient修饰,表示该数组默认不会被序列化。通过重写writeObject()方法来只序列化数组中有元素填充的那部分。

    (d)Fair-Fast机制:用modCount来记录ArrayList结构发生变化的次数,在进行序列化或者迭代操作时,需要比较操作前后modCount是否改变,如果改变了需要抛出ConcurrentModificationException。序列的结构性变化指add()或remove()一个元素或者调整内部数组的大小(trimToSize(),ensureExplicitCapacity()),仅仅设置元素值不算结构发生改变。

    private void writeObject(java.io.ObjectOutputStream s)
        throws java.io.IOException{
        // Write out element count, and any hidden stuff
        int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    } int expectedModCount = modCount;
        s.defaultWriteObject();

        // Write out size as capacity for behavioural compatibility with clone()
        s.writeInt(size);

        // Write out all elements in the proper order.
        for (int i=0; i<size; i++) {
            s.writeObject(elementData[i]);
        }

        if (modCount != expectedModCount) {
            throw new ConcurrentModificationException();
        }
    }

    (e)和Vector的区别

        Vector 和 ArrayList 几乎是完全相同的,唯一的区别在于 Vector 是同步的,因此开销就比 ArrayList 要大,访问速度更慢。Vector 每次扩容请求其大小的 2 倍空间,而 ArrayList 是 1.5 倍。

       为了获得线程安全的 ArrayList,可以调用 Collections.synchronizedList(new ArrayList<>()); 返回一个线程安全的 ArrayList,也可以使用 concurrent 包下的 CopyOnWriteArrayList 类;

    (f)和LinkedList的区别:LinkedList双端链表实现,只支持顺序访问访问O(n),利于插入删除操作O(1)。

2.HashMap

    (a)存储结构:使用拉链法来解决hash冲突。内部包含了一个Entry类型的数组,存储每个链的头结点,头结点不含有效数据。关于hash冲突有拉链法,再hash,平方散列等处理方式。

    (b)默认长度为16(1<<4),默认装载因子为0.75,阈值=Entry.length*装载因子;Entry最大允许大小Max_Capacity为2的30次方,每次resize为原来的2倍,当不能在resize时,阈值调整为Integer.MAX_VALUE;允许null键,null键默认存放在0位置,null键只能保存最新值。

    (b)hash值的计算:hashCode()的高16位异或hashCode()的低16位。return key==null?0:(h=key.hashCode())^(h>>>16)。

    (c)所属桶的计算:拉链法需要用除余法来得到桶的下标,即bucketIndex=hash%capacity,如果能够保证capacity为2的幂次方,那么该hash取余运算就可以转化为位与运算bucketIndex=hash & (capacity-1)。提高运算效率。

    static int indexFor(int h, int length) {
        // assert Integer.bitCount(length) == 1 : "length must be a non-zero power of 2";
        return h & (length-1);
    }
    public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);

        this.loadFactor = loadFactor;
        threshold = initialCapacity;//构造器的initialCapacity实际上是阈值
      init();

}

    public V put(K key, V value) {//1.insert || update
        if (table == EMPTY_TABLE) {
            inflateTable(threshold);
        }
        if (key == null)//2.若key==null,约定放在第一个桶
            return putForNullKey(value);//若已经存在key==null的结点,则更新它的值;若不存在,新插一个结点,因此key==null的结点始终只能保存最新的值
        int hash = hash(key);
        int i = indexFor(hash, table.length);
        for (Entry<K,V> e = table[i]; e != null; e = e.next) {//update
            Object k;
            if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                V oldValue = e.value;
                e.value = value;
                e.recordAccess(this);
                return oldValue;
            }
        }
        //insert
        modCount++;
        addEntry(hash, key, value, i);//头插法
        return null;
    }

 

3.HashSet:借助HashMap来实现,准确来说是借助HashMap的key的唯一性来实现。用一个通用对象作为value的占位符。

4.TreeMap:可以实现key有序的map,用红黑树组织数据,红黑树是弱平衡的二叉搜索树,插入、查找元素简单点可以参二叉搜索树的对应操作;拿到有序key,可以通过非递归中序遍历(bst树中序遍历得到的是一个有序序列)。

https://blog.csdn.net/away_lit/article/details/79600327

5.LinkedHashMap:HashMap的子类,可以实现插入顺序有序。直观的看可以认为是链表+map,用链表维护元素的插入顺序,用map存储k-v对。实际实现上就是对HashMap的Entry改造了下,加了个后继结点索引,并全局保存最后添加的元素。

6.ConcurrentHashMap:对HashTable的改进,采用分段加锁,减小锁的作用域,提高并发度,默认为16段。

 

 

 

 

https://github.com/CyC2018/Interview-Notebook/blob/master/notes/Java%20%E5%AE%B9%E5%99%A8.md#arraylist

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值