Java集合源码—ArrayList

  1. java泛型

E - Element (在集合中使用,因为集合中存放的是元素)

T - Type(Java 类)

K - Key(键)

V - Value(值)

N - Number(数值类型)

? - 表示不确定的java类型

Java源码中的Class代表这个类型所对应的类,而Class<?>表示类型不确定的类。

ArrayList提供了一个将List转为数组的一个非常方便的方法 list.toArray(),是将list直接转为Object[] 数组。

  1. Arrays.copyOf()

Array.copyOf() 用于复制指定的数组内容以达到扩容的目的,该方法对不同的基本数据类型都有对应的重载方法.
在这里插入图片描述
4. equals()方法

Object类的equals方法就是==,基本数据类型比较的是值是否相等,引用类型数据比较的是引用对象的内存地址是否一样。String类重写了equals方法,比较的是两个量的值是否相等。

  1. ArrayList与LinkedList、Vector对比区别

分析得出下面结论:

(1)ArrayList 本质上是一个可改变大小的数组.当元素加入时,其大小将会动态地增长.内部的元素可以直接通过get与set方法进行访问.元素顺序存储 ,随机访问很快,删除非头尾元素慢,新增元素慢而且费资源 ,较适用于无频繁增删的情况 ,比数组效率低,如果不是需要可变数组,可考虑使用数组 ,非线程安全.

(2)LinkedList 是一个双链表,在添加和删除元素时具有比ArrayList更好的性能.但在get与set方面弱于ArrayList. 适用于 :没有大规模的随机读取,有大量的增加/删除操作.随机访问很慢,增删操作很快,不耗费多余资源 ,允许null元素,非线程安全.

(3)Vector (类似于ArrayList)但其是同步的,开销就比ArrayList要大。如果你的程序本身是线程安全的,那么使用ArrayList是更好的选择。 Vector和ArrayList在更多元素添加进来时会请求更大的空间。Vector每次请求其大小的双倍空间,而ArrayList每次对size增长50%.

  1. ArrayList的扩容机制

ArrayList的扩容有两个位置

(1)使用无参构造创建集合,第一次添加元素时,会对集合进行判断,如果为空,则对添加元素所需的容量与默认容量进行比较,默认容量为10

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        //当集合为空时
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }

    private void ensureCapacityInternal(int minCapacity) {
        ensureExplicitCapacity(calculateCapacity(elementData, minCapacity));
    }

    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

(2)添加元素时,容量不足时,会进行扩容。此为核心扩容机制

 public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
 private void grow(int minCapacity) {
        int oldCapacity = elementData.length;

        // 新的容量为旧容量的1.5倍
        int newCapacity = oldCapacity + (oldCapacity >> 1);

        // 如果新容量小于所需的最小容量,则扩容后的容量为所需最小的容量
        if (newCapacity - minCapacity < 0){
            newCapacity = minCapacity;
        }

        // 如果新容量大于集合限制的最大容量,则进入另一判断:看所需的容量大小
        if (newCapacity - MAX_ARRAY_SIZE > 0){
            newCapacity = hugeCapacity(minCapacity);
        }
        // 创建一个新的数组,将旧数组copy进去
        elementData = Arrays.copyOf(elementData, newCapacity);
    }

    private static int hugeCapacity(int minCapacity) {
        if (minCapacity < 0) // overflow
            throw new OutOfMemoryError();
        return (minCapacity > MAX_ARRAY_SIZE) ?
            Integer.MAX_VALUE :
            MAX_ARRAY_SIZE;
    }
  1. batchRemove()方法详解

在这里插入图片描述

  1. ArrayList中的序列化

序列化:将对象转化为字节的过程称为序列化过程。
反序列化:将字节转化为对象的过程称为反序列化。

序列化主要应用于网络传输和数据存储的场景。

有些时候,我们有这样的需求,某些属性不需要序列化。怎么做?使用transient关键字选择不需要序列化的字段。

使用transient虽然简单,但是将此属性完全隔离在了序列化之外。有没有一种机制,可以定制对象序列化的方式?通过重写writeObject与readObject方法,可以自己选择哪些属性需要序列化, 哪些属性不需要。如果writeObject使用某种规则序列化,则相应的readObject需要相反的规则反序列化,以便能正确反序列化出对象。

在new一个ArrayList对象时,默认是开辟一个长度为10的对象数组,如果只存入几个对象(不到默认的10个),如果采用默认序列化,则会将其余为null也序列化到文件中。

如果声明为transient类型,就能让虚拟机不会自行处理我们的这个数组,这才有了ArrayList的write/readObject方法。通过这种方式避免了浪费资源去存储没有的数据。重写完write/readObject方法后,ArrayList对象中只有不为null的元素才会序列化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值