彻底认识Java数组和ArrayList

数组

  1. 数组在Java中是一个对象,数组实例同样是使用new操作符创建的。Array.length指定了数组长度
  2. 数组索引起始为0,负数索引在Java中是无效的,会抛出ArrayIndexOutOfBoundException
  3. 数组存储在Java堆连续内存空间,所以如果你创建一个大的索引,你可以有足够的堆空间直到抛出OutofmemoryError,因为请求的内存大小在连续的内存空间不可用。
  4. 数组一个固定长度 的数据结构,一旦声明,你不能改变数组的长度。
  5. 不同类型的数组有不同的类型。eg:int[] 为[I 、float[][]为[[F。如果是对象数组:String[]为[Ljava.lang.String;
  6. 如果没有明确的初始化数组元素,那么数组就会用默认的类型值初始化,例如假若没有初始化整型数组,元素都将默认值为0,没有初始化的boolean值是false,对象数组是null。
  7. 你可以通过使用[]操作符访问数组元素,因为数组索引起始于0,[0]返回第一个元素,[length-1]返回最后一个元素,for循环是一种迭代整个数组便捷方法。你可以使用for循环初始化整个数组、访问的每个索引或更新、获取数组元素。Java5以后同样提供了加强的for(foreach)循环,数组自己管理索引,防止ArrayIndexOutOfBoundException
  8. Java中数组可以轻易的转换成ArrayList。ArrayList一个基于索引的集合,它是作为数组的备选方案。ArrayList的优点是可以改变容量大小,只需要创建个更大的数组然后拷贝内容到新数组,但你不能改变数组的大小。
int[] numbers = new int[]{10, 20, 30, 40, 50};
 
//传统for
for (int i = 0; i < numbers.length; i++) {
  System.out.println("element at index " + i + ": " + numbers[i]);
}

//加强for
for(int i: numbers){
   System.out.println(i);
}

 

 

我们知道,在java中数组就是一个特殊的对象。

那他到底什么特殊呢?

String [] a = new String[10];
int b = a.length;
Class clazz = a.getClass();   
System.out.println(clazz.getName()); 	
System.out.println(clazz.getDeclaredFields().length);   
System.out.println(clazz.getDeclaredMethods().length);   
System.out.println(clazz.getDeclaredConstructors().length);   
System.out.println(clazz.getDeclaredAnnotations().length);   
System.out.println(clazz.getDeclaredClasses().length);   
System.out.println(clazz.getSuperclass());

可见 这个类为[Ljava.lang.String;

这个类是java.lang.Object的直接子类

自身没有声明任何成员变量、成员方法、构造函数和Annotation

 

ArrayList

ArrayList有以下属性


    private static final int DEFAULT_CAPACITY = 10;    //默认容器大小
    private static final Object[] EMPTY_ELEMENTDATA = {}; //默认容器元素
    /**
     * 我们将其与EMPTY_ELEMENTDATA区分开来,以便在添加第一个元素时知道要膨胀多少。
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};//默认容器元素
    transient Object[] elementData; // non-private to simplify nested class access
    private int size;        //实际存放数据的长度
    private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;    //数组的最大长度

1.初始化,注意注释,初始化时 容器大小为10。添加第一个元素时,将扩展为DEFAULT_CAPACITY。

可以发现,无参初始化使用 DEFAULTCAPACITY_EMPTY_ELEMENTDATA

有参而参数为0时使用EMPTY_ELEMENTDATA初始化。

    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
    private static final Object[] EMPTY_ELEMENTDATA = {}; 
    /**
     * Constructs an empty list with an initial capacity of ten.
     */
    public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

    public ArrayList(int initialCapacity) {
        if (initialCapacity > 0) {
            this.elementData = new Object[initialCapacity];
        } else if (initialCapacity == 0) {
            this.elementData = EMPTY_ELEMENTDATA;
        } else {
            throw new IllegalArgumentException("Illegal Capacity: "+
                                               initialCapacity);
        }
    }

 2.添加数组。add()

阅读源码后可以发现一般情况下一个容量为n的数组应该扩容为n+n/2

当计算出来的n+n/2大于MAX_ARRAY_SIZE时。

minCapacity小于MAX_ARRAY_SIZE 直接扩容到MAX_ARRAY_SIZE。

minCapacity大于MAX_ARRAY_SIZE,时 直接扩容至Integer.MAX_VALUE。

    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  // 扩容
        elementData[size++] = e;
        return true;
    }

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

    /**
    * 返回要至少容器空间的大小
    * 如果该数组为空,返回DEFAULT_CAPACITY = 10 和 minCapacity的最大值。
    * 如果数组不为空 直接返回minCapacity
    **/
    private static int calculateCapacity(Object[] elementData, int minCapacity) {
        if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
            return Math.max(DEFAULT_CAPACITY, minCapacity);
        }
        return minCapacity;
    }



    /**
    *    判断最小容器大小是否大于原先数组个数。这里应该是防止错误出现的一种校验?
    *    大于:进行扩容
    *    小于:结束操作。
    **/
    private void ensureExplicitCapacity(int minCapacity) {
        modCount++;    //表示数组在扩容中....
        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            grow(minCapacity);
    }

    /**
     * 扩容 并复制到新的数组
     * 
     * @param minCapacity the desired minimum capacity
     */
    private void grow(int minCapacity) {
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);
        if (newCapacity - minCapacity < 0)
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        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;
    }

3.删除元素remove()

    public E remove(int index) {
        rangeCheck(index);

        modCount++;
        E oldValue = elementData(index);

        int numMoved = size - index - 1;
        if (numMoved > 0)
            System.arraycopy(elementData, index+1, elementData, index,
                             numMoved);
        elementData[--size] = null; // clear to let GC do its work

        return oldValue;
    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值