Java集合深入学习 - ArrayList源码解析-1基础(基于jdk1.8)
Java集合深入学习 - ArrayList源码解析-2序列化与迭代器(基于jdk1.8)
Java集合深入学习 - ArrayList源码解析-3子List与坑点(基于jdk1.8)
1.内部类SubList解析
ArrayList中定义了一个内部类,用来暴露集合的部分数据,其定义代码如下:
/**
* 定义一个视图类,展示集合的部分数据 继承自AbstractList实现RandomAccess接口
*/
private class SubList extends AbstractList<E> implements RandomAccess {
private final AbstractList<E> parent; //父类的引用
private final int parentOffset; //父数组偏移量
private final int offset; //偏移量
int size; //视图大小
/**
* 构造方法
* @param parent
* @param offset
* @param fromIndex
* @param toIndex
*/
SubList(AbstractList<E> parent,
int offset, int fromIndex, int toIndex) {
this.parent = parent;
this.parentOffset = fromIndex;
this.offset = offset + fromIndex;
this.size = toIndex - fromIndex;
this.modCount = ArrayList.this.modCount;
}
}
其中定义了如下的方法
观察其源码可发现,针对SubList的操作(增删改查)都是直接操作在ArrayList上的,部分代码如下:
/**
* 修改数据
*/
public E set(int index, E e) {
rangeCheck(index); //校验index位置
checkForComodification(); //校验操作次数
E oldValue = ArrayList.this.elementData(offset + index); //获取父类中对应位置的数据
ArrayList.this.elementData[offset + index] = e; //直接修改父数组中的数据 注:原数组数据会发生改变
return oldValue; //返回修改前的数据
}
/**
* 获取数据
*/
public E get(int index) {
rangeCheck(index);
checkForComodification();
return ArrayList.this.elementData(offset + index);
}
/**
* 获取大小
*/
public int size() {
checkForComodification();
return this.size;
}
/**
* 添加数据
*/
public void add(int index, E e) {
rangeCheckForAdd(index); //校验index
checkForComodification();
parent.add(parentOffset + index, e); //调用父类添加数据方法添加数据
this.modCount = parent.modCount;
this.size++;
}
/**
* 移除数据
*/
public E remove(int index) {
rangeCheck(index);
checkForComodification();
E result = parent.remove(parentOffset + index);
this.modCount = parent.modCount;
this.size--;
return result;
}
获取SubList的方式:
/**
* 获取当前集合部分数据的一个视图,数据为重fromIndex到toIndex
*/
public List<E> subList(int fromIndex, int toIndex) {
subListRangeCheck(fromIndex, toIndex, size);
return new SubList(this, 0, fromIndex, toIndex);
}
/**
* 大小关系校验 对应大小关系应为:0 < fromIndex < toIndex < size
*/
static void subListRangeCheck(int fromIndex, int toIndex, int size) {
if (fromIndex < 0)
throw new IndexOutOfBoundsException("fromIndex = " + fromIndex);
if (toIndex > size)
throw new IndexOutOfBoundsException("toIndex = " + toIndex);
if (fromIndex > toIndex)
throw new IllegalArgumentException("fromIndex(" + fromIndex +
") > toIndex(" + toIndex + ")");
}
2.坑点
2.1 另一个ArrayList之Arrays.asList
/**
* Arrays.asList根据动态传入的参数 生成一个ArrayList
* @param a 动态参数 接收为 T[] 数组
*/
@SafeVarargs
@SuppressWarnings("varargs")
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
/**
* Arrays中的内部类ArrayList继承AbstractList实现RandomAccess和Serializable
*/
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable{}
Arrays.ArrayList中实现的方法如下:
观察可发现,Arrays.ArrayList中并没有实现add/remove等方法,如果调用其add方法或remove方法,会调用到AbstractList中的方法,会直接抛出异常,其代码如下:
/**
* AbstractList.add
*/
public boolean add(E e) {
add(size(), e);
return true;
}
/**
* AbstractList.add
*/
public void add(int index, E element) {
throw new UnsupportedOperationException();
}
/**
* AbstractList.remove
*/
public E remove(int index) {
throw new UnsupportedOperationException();
}
2.2 数据处理都只是浅拷贝?
细读ArrayList源码,涉及到数据拷贝的地方有很多,其中大致调用了两个方法System.arraycopy和Arrays.copyOf,观察其源码会发现,其实Arrays.copyOf的处理也是调用了System.arraycopy方法,代码如下:
/**
* Arrays.copyOf
*/
@SuppressWarnings("unchecked")
public static <T> T[] copyOf(T[] original, int newLength) {
return (T[]) copyOf(original, newLength, original.getClass());
}
/**
* Arrays.copyOf
*/
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
@SuppressWarnings("unchecked")
T[] copy = ((Object)newType == (Object)Object[].class)
? (T[]) new Object[newLength]
: (T[]) Array.newInstance(newType.getComponentType(), newLength);
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
所以,需要特别注意的地方有如下:
//该集合不能够进行增删操作
List<Demo> list = Arrays.asList(new Demo("111"),new Demo("222"),new Demo("333"));
List list1 = new ArrayList<>();
list1.add("");//添加数据
//这种方式创建的数组 源集合中数据发生改变时,list2中的数据也会发生改变
List list2 = new ArrayList<>(list1);
List list3 = new ArrayList<>();
//这两种方式创建的数组 源集合中数据发生改变时,list3中的数据也会发生改变
list3.addAll(list2);
list3.addAll(0, list2);
//objs中数据发生改变,list3中数据也会发生改变
Object[] objs = list3.toArray();
本文连接,转载请标注https://blog.csdn.net/luo_mu_hpu/article/details/106216169