数组
- 数组在Java中是一个对象,数组实例同样是使用new操作符创建的。Array.length指定了数组长度
- 数组索引起始为0,负数索引在Java中是无效的,会抛出ArrayIndexOutOfBoundException
- 数组存储在Java堆的连续内存空间,所以如果你创建一个大的索引,你可以有足够的堆空间直到抛出OutofmemoryError,因为请求的内存大小在连续的内存空间不可用。
- 数组一个固定长度 的数据结构,一旦声明,你不能改变数组的长度。
- 不同类型的数组有不同的类型。eg:int[] 为[I 、float[][]为[[F。如果是对象数组:String[]为[Ljava.lang.String;
- 如果没有明确的初始化数组元素,那么数组就会用默认的类型值初始化,例如假若没有初始化整型数组,元素都将默认值为0,没有初始化的boolean值是false,对象数组是null。
- 你可以通过使用[]操作符访问数组元素,因为数组索引起始于0,[0]返回第一个元素,[length-1]返回最后一个元素,for循环是一种迭代整个数组便捷方法。你可以使用for循环初始化整个数组、访问的每个索引或更新、获取数组元素。Java5以后同样提供了加强的for(foreach)循环,数组自己管理索引,防止ArrayIndexOutOfBoundException
- 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;
}