Java-手写ArrayList集合
1.Arraylist数组存储对象实现原理
Jdk1.8源代码中
其实ArrayList是用Object[]数组实现。
这里我们有些轮子也不用完全自己造了,可以参考jdk源码,实现核心代码即可。
2.首先介绍ArrayList中的几个核心方法原理
2.1添加元素
普通添加,list.add(Object),元素添加在数组的最后
在指定脚标位置添加元素,list.add(index,Object),如果在脚标3的位置插入,则4以后的元素全部往后移动一位
2.2删除元素
list.remove(Object),删除位置为4的元素,则4以后的元素全部往前移动一位
2.3数组扩容
Object[]数组是有默认大小的,如果添加的元素长度超过数组长度,需要进行扩容。
jdk1.8扩容机制为原来长度的1.5倍,>>1 位移符 可以理解为*0.5
3.实现源代码
本文中只实现,add(),remove(),get()等基本方法。
package com.huajie.arrayList;
import java.util.AbstractList;
import java.util.Arrays;
/**
* 手写arraylist 数组集合
* 1.扩容技术 1.5倍
* 2.数组复制
* 与vertor区别 vertor线程安全 但是效率慢 操作方法都加了 同步 ,扩容2倍
* @author xiewenfeng
*
* @param <E>
*/
public final class XwfArrayList<E> extends AbstractList<E> {
// 底层采用数据存放
private Object[] elementData;
// 默认空数组
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
// 默认数组容量
private static final int DEFAULT_CAPACITY = 2;
// 时间ArrayList大小
private int size;
public XwfArrayList(int initialCapacity) {
// 初始容量
if (initialCapacity > 0) {
elementData = new Object[initialCapacity];
} else if (initialCapacity == 0) {
elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
} else {
throw new RuntimeException("创建数组初始长度不能为负数");
}
}
/**
* JDK1.7之后 初始化 放在 ADD方法里面
*/
public XwfArrayList() {
elementData = new Object[DEFAULT_CAPACITY];
}
public boolean add(Object obj) {
// 扩容
ensureExplicitCapacity(size + 1);
// 2.使用下标赋值
elementData[size++] = obj;
return true;
}
/**
* 扩容
*
* @param minCapacity
*/
private void ensureExplicitCapacity(int minCapacity) {
// 1.判断容量
if (size == elementData.length) {
int oldCapacity = size;
int newCapacity = oldCapacity + (oldCapacity >> 1);
// 初始最小容量
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
elementData = Arrays.copyOf(elementData, newCapacity);
}
}
@SuppressWarnings("unchecked")
public E get(int index) {
rangeCheck(index);
return (E) elementData[index];
}
private void rangeCheck(int index) {
if (index >= size)
throw new IndexOutOfBoundsException("数组脚标越界");
}
public int size() {
return size;
}
public E remove(int index) {
rangeCheck(index);
// 拿到要删除的数据
E object = get(index);
// 需要复制的长度 index后面
int numMoved = size - index - 1;
// 从第几位开始复制 index+1
int srcPos = index + 1;
// 移动到第几位
int destPos = index;
if (numMoved > 0) {
System.arraycopy(elementData, srcPos, elementData, destPos, numMoved);
}
// 最后一位删除
elementData[--size] = null;
return object;
}
/**
* 删除对象
*
* @param obj
* @return
*/
public boolean remove(Object obj) {
for (int i = 0; i < elementData.length; i++) {
Object value = elementData[i];
if (value.equals(obj)) {
remove(i);
return true;
}
}
return false;
}
/**
* 插入对象
*
* @param obj
* @return
*/
public void add(int index, Object obj) {
rangeCheck(index);
// 扩容
ensureExplicitCapacity(size + 1);
// 复制数组后移一位
System.arraycopy(elementData, index, elementData, index + 1, size - index);
// 2.使用下标赋值
elementData[index] = obj;
size++;
}
/**
* 清空数组
*/
public void clear() {
for (int i = 0; i < elementData.length; i++) {
elementData[i] = null;
}
size = 0;
}
}
代码中有两段取自jdk源码实现,可以用其他代码实现,jdk源码中的效率更高。
第一段:
扩容的复制数组,可以用以下代码替换
Object[] old = elementData;
elementData = new Object[newCapacity];
for (int i = 0; i < size; i++) {
elementData[i] = old[i];
}
第二段:
数组向后移动一位,可以用以下代码替换
for (int i = size; i > index; i--) {
elementData[i] = elementData[i-1];
}
同理还有remove中的,如果使用原始的for循环,系统开销比较大。
4.测试
package com.huajie.arrayList;
public class Test001 {
public static void main(String[] args) {
XwfArrayList<String> a = new XwfArrayList<String>();
a.add("haha1");
a.add("haha2");
a.add("haha3");
a.add("haha4");
a.add("haha5");
for (int i = 0; i < a.size(); i++) {
System.out.println(a.get(i));
}
System.out.println("==========================");
Object remove = a.remove(2);
System.out.println("删除的元素" + remove);
for (int i = 0; i < a.size(); i++) {
System.out.println(a.get(i));
}
System.out.println("==========================");
a.add(2, "新插入");
for (String string : a) {
System.out.println(string);
}
}
}