一、简介
ArrayList是经典而又常用的数据结构,说白了就是非线程安全的动态数组,相比于数组长度不可改变的特点,ArrayList可以动态的增删数据而无需考虑数组大小,因为它的内部对数组的处理做了一些封装;
ArrayList实现机制,简单来说:内部维护了一个Array数组(elementData)保存数据,当长度不够时则创建一个更大的数组,并把原数组复制过去,并对其它的一些操作进行了很好的封装,下面就是我自己实现的一个简单的动态数组。
二、自己写一个简单的ArrayList
1. 初始化和构造函数
真正存储数据的数组 Object[] elements;
设置默认数组elements大小为8(源码为10)
数组最大容量为Integer.MAX_VALUE - 8,java虚拟机要保留有关信息在数组中,所以预留8个位置
提供两个构造方法,有参的设置大小,无参的调用有参的,设置数组大小为默认值
代码:
/**
* 默认数组大小
*/
private static final int DEFAULT_SIZE = 8;
/**
* 数组最大容量,VM要保留数组头部信息在数组中,所以预留8个位置
*/
private static final int MAX_SIZE = Integer.MAX_VALUE - 8;
/**
* 数组大小
*/
private int size;
private Object[] elements;
public YhArrayList() {
this(DEFAULT_SIZE);
}
public YhArrayList(int size) {
if (size < 0) {
throw new IllegalArgumentException("不合法的初始化大小:" + size);
} else {
elements = new Object[size];
}
}
2. contains()、indexOf()、isEmpty()、get()等方法
代码:
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == o) {
return i;
}
}
} else {
for (int i = 0; i < size; i++) {
if (o.equals(elements[i])) {
return i;
}
}
}
return -1;
}
/**
* 检查是否越界,越界则抛出异常
* @param index
*/
private void checkRange(int index) {
if (index < 0 || index > MAX_SIZE) {
throw new IndexOutOfBoundsException("数组越界:index == " + index);
}
}
public Y get(int index) {
checkRange(index);
return (Y) elements[index];
}
3.add()方法
核心是通过ensureCapacity(int size)方法保证size大小,其内部调用explicitCapacity(int size)实现自动扩容(1.5倍)。
代码:
ensureCapavity()和explicitCapacity():
/**
* 判断是否需要扩容
* size>Integer.MAX_VALUE时变负,所以增加size<0的判断
*
* @param size
*/
private void ensureCapacity(int size) {
if (size > DEFAULT_SIZE) {
explicitCapacity(size);
}
if (size < 0) {
throw new IndexOutOfBoundsException("数组越界:size == " + size);
}
}
/**
* 真正实现扩容
* 先扩容1.5倍,若还小于申请长度,则扩容为所申请的长度,若大于最大长度,则设为最大长度
* 调用Arrays.copyOf()实现数组的复制,参数是被复制的数组和复制的长度,返回的是复制后的数组
* (复制的长度大于被复制数组的长度,用类型的默认值填充)
*
* @param size
*/
private void explicitCapacity(int size) {
int oldCapacity = elements.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity < size) {
newCapacity = size;
}
if (newCapacity > MAX_SIZE) {
newCapacity = MAX_SIZE;
}
elements = Arrays.copyOf(elements, newCapacity);
}
add()方法:
public void add(Y y) {
//扩容操作
ensureCapacity(size + 1);
//将对象添加到size位置,并将size+1
elements[size++] = y;
}
public void add(int index, Y y) {
//判断index是否越界
checkRange(index);
//保证大小(如果需要,自动扩容)
ensureCapacity(size + 1);
//将elements中从index往后的size-index个元素向后移一位(移动到elements的从index+1往后的size-index个位置中)
System.arraycopy(elements, index, elements, index + 1, size - index);
}
4. remove()方法
代码:
/**
* 判断index后面元素个数,若大于0则将他们前移一位,将size减一,将原最后一位置空
*
* @param index
* @return
*/
public Y remove(int index) {
Y y = get(index);
int moveSize = size - index - 1;
if (moveSize > 0) {
System.arraycopy(elements, index + 1, elements, index, size - index - 1);
}
elements[--size] = null;
return y;
}
/**
* 配合contains()和remove()实现,返回值为是否删除成功
* @param o
* @return
*/
public boolean remove(Object o) {
if (contains(o)) {
remove(indexOf(o));
return true;
} else {
return false;
}
}
三、完整源码
package com.yh.datamaker.list;
import java.util.Arrays;
/**
* @author: YH
* @date: 2018/7/8 0008
* @function 自己实现动态数组YhArrayList
*/
public class YhArrayList<Y> {
/**
* 默认数组大小
*/
private static final int DEFAULT_SIZE = 8;
/**
* 数组最大容量,VM要保留数组头部信息在数组中,所以预留8个位置
*/
private static final int MAX_SIZE = Integer.MAX_VALUE - 8;
/**
* 数组大小
*/
private int size;
private Object[] elements;
public YhArrayList() {
this(DEFAULT_SIZE);
}
public YhArrayList(int size) {
if (size < 0) {
throw new IllegalArgumentException("不合法的初始化大小:" + size);
} else {
elements = new Object[size];
}
}
public int size() {
return size;
}
public boolean isEmpty() {
return size == 0;
}
public boolean contains(Object o) {
return indexOf(o) != -1;
}
public int indexOf(Object o) {
if (o == null) {
for (int i = 0; i < size; i++) {
if (elements[i] == o) {
return i;
}
}
} else {
for (int i = 0; i < size; i++) {
if (o.equals(elements[i])) {
return i;
}
}
}
return -1;
}
/**
* 检查是否越界,越界则抛出异常
* @param index
*/
private void checkRange(int index) {
if (index < 0 || index > MAX_SIZE) {
throw new IndexOutOfBoundsException("数组越界:index == " + index);
}
}
public Y get(int index) {
checkRange(index);
return (Y) elements[index];
}
public void add(Y y) {
//扩容操作
ensureCapacity(size + 1);
//将对象添加到size位置,并将size+1
elements[size++] = y;
}
public void add(int index, Y y) {
//判断index是否越界
checkRange(index);
//保证大小(如果需要,自动扩容)
ensureCapacity(size + 1);
//将elements中从index往后的size-index个元素向后移一位(移动到elements的从index+1往后的size-index个位置中)
System.arraycopy(elements, index, elements, index + 1, size - index);
}
/**
* 判断是否需要扩容
* size>Integer.MAX_VALUE时变负,所以增加size<0的判断
*
* @param size
*/
private void ensureCapacity(int size) {
if (size > DEFAULT_SIZE) {
explicitCapacity(size);
}
if (size < 0) {
throw new IndexOutOfBoundsException("数组越界:size == " + size);
}
}
/**
* 真正实现扩容
* 先扩容1.5倍,若还小于申请长度,则扩容为所申请的长度,若大于最大长度,则设为最大长度
* 调用Arrays.copyOf()实现数组的复制,参数是被复制的数组和复制的长度,返回的是复制后的数组
* (复制的长度大于被复制数组的长度,用类型的默认值填充)
*
* @param size
*/
private void explicitCapacity(int size) {
int oldCapacity = elements.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity < size) {
newCapacity = size;
}
if (newCapacity > MAX_SIZE) {
newCapacity = MAX_SIZE;
}
elements = Arrays.copyOf(elements, newCapacity);
}
/**
* 判断index后面元素个数,若大于0则将他们前移一位,将size减一,将原最后一位置空
*
* @param index
* @return
*/
public Y remove(int index) {
Y y = get(index);
int moveSize = size - index - 1;
if (moveSize > 0) {
System.arraycopy(elements, index + 1, elements, index, size - index - 1);
}
elements[--size] = null;
return y;
}
/**
* 配合contains()和remove()实现,返回值为是否删除成功
* @param o
* @return
*/
public boolean remove(Object o) {
if (contains(o)) {
remove(indexOf(o));
return true;
} else {
return false;
}
}
}