目录
定义
数组是一个固定大小的容器,由一组元素(值或变量)组成的数据结构,每个元素有至少一个索引或键来标识。
特点:
- 固定大小:一旦数组被创建,其大小就固定不变。要增加或减少数组的大小,需要创建一个新的数组并将原数组的元素复制到新数组中。
- 存储相同类型的元素:数组中的元素必须是相同类型的,即数组是同类型的集合。
- 连续内存空间:数组中的元素在内存中是连续存储的,这也是数组访问速度快的一个重要原因。
- 下标访问:数组中的元素通过下标来访问,下标从0开始,最后一个元素的下标为数组长度减1。
空间占用
Java 中数组结构为
-
8 字节 markword 用来存储该数组的地址
-
4 字节 class 指针(压缩 class 指针的情况)
-
4 字节 数组大小(决定了数组最大容量是 2^{32})
-
数组元素 + 对齐字节(java 中所有对象大小都是 8 字节的整数倍,不足的要用对齐字节补足)
例如
int[] array = {1, 2, 3, 4, 5};
的大小为 40 个字节,组成如下
8 + 4 + 4 + 5*4 + 4(alignment)
动态数组
动态数组在数组的基础上实现了自动扩容的功能
public class DynamicArray implements Iterable<Integer> {
private int size = 0; // 逻辑大小
private int capacity = 8; // 容量
private int[] array = {};
/**
* 向最后位置 [size] 添加元素
*
* @param element 待添加元素
*/
public void addLast(int element) {
add(size, element);
}
/**
* 向 [0 .. size] 位置添加元素
*
* @param index 索引位置
* @param element 待添加元素
*/
public void add(int index, int element) {
checkAndGrow();
// 添加逻辑
if (index >= 0 && index < size) {
// 向后挪动, 空出待插入位置
System.arraycopy(array, index,
array, index + 1, size - index);
}
array[index] = element;
size++;
}
private void checkAndGrow() {
// 容量检查
if (size == 0) {
array = new int[capacity];
} else if (size == capacity) {
// 进行扩容, 1.5 1.618 2
capacity += capacity >> 1;
int[] newArray = new int[capacity];
System.arraycopy(array, 0,
newArray, 0, size);
array = newArray;
}
}
/**
* 从 [0 .. size) 范围删除元素
*
* @param index 索引位置
* @return 被删除元素
*/
public int remove(int index) { // [0..size)
int removed = array[index];
if (index < size - 1) {
// 向前挪动
System.arraycopy(array, index + 1,
array, index, size - index - 1);
}
size--;
return removed;
}
/**
* 查询元素
*
* @param index 索引位置, 在 [0..size) 区间内
* @return 该索引位置的元素
*/
public int get(int index) {
return array[index];
}
/**
* 遍历方法1
*
* @param consumer 遍历要执行的操作, 入参: 每个元素
*/
public void foreach(Consumer<Integer> consumer) {
for (int i = 0; i < size; i++) {
// 提供 array[i]
// 返回 void
consumer.accept(array[i]);
}
}
/**
* 遍历方法2 - 迭代器遍历
*/
@Override
public Iterator<Integer> iterator() {
return new Iterator<Integer>() {
int i = 0;
@Override
public boolean hasNext() { // 有没有下一个元素
return i < size;
}
@Override
public Integer next() { // 返回当前元素,并移动到下一个元素
return array[i++];
}
};
}
/**
* 遍历方法3 - stream 遍历
*
* @return stream 流
*/
public IntStream stream() {
return IntStream.of(Arrays.copyOfRange(array, 0, size));
}
}
二位数组
二维数组的实质是将一维数组的每个元素的值改为每个数组的地址
-
二维数组占 32 个字节,其中 array[0],array[1],array[2] 三个元素分别保存了指向三个一维数组的引用
-
三个一维数组各占 40 个字节
-
它们在内层布局上是连续的