专业编程基础技术教程

网站首页 > 基础教程 正文

java基础之ArrayList(java里面arraylist)

ccvgpt 2024-08-01 11:34:39 基础教程 8 ℃

ArrayList是数组元素常用的数据结构,比较简单。

主要从以下几点总结以下该结构。

java基础之ArrayList(java里面arraylist)

ArrayList的基本属性:

//对象数组:ArrayList的底层数据结构,用于存放数据,

private transient Object[] elementData;

//elementData中已存放的元素的个数,注意:不是elementData的容量

private int size;

是不是对transient的使用有点迷糊?下面讲到

ArrayList的内容序列化

transient关键字的作用:在采用Java默认的序列化机制的时候,被该关键字修饰的属性不会被序列化。

ArrayList类实现了java.io.Serializable接口,即采用了Java默认的序列化机制

上面的elementData属性采用了transient来修饰,表明其不使用Java默认的序列化机制来实例化,但是该属性是ArrayList的底层数据结构,在网络传输中一定需要将其序列化,之后使用的时候还需要反序列化,那不采用Java默认的序列化机制,那采用什么呢序列化方式呢?

源码有两个方法,ArrayList自己实现了序列化和反序列化

/**

* Save the state of the <tt>ArrayList</tt> instance to a stream (that is,

* serialize it).

*

* @serialData The length of the array backing the <tt>ArrayList</tt>

* instance is emitted (int), followed by all of its elements

* (each an <tt>Object</tt>) in the proper order.

*/

private void writeObject(java.io.ObjectOutputStream s)

throws java.io.IOException {

// Write out element count, and any hidden stuff

int expectedModCount = modCount;

s.defaultWriteObject();

// Write out array length

s.writeInt(elementData.length);

// Write out all elements in the proper order.

for (int i = 0; i < size; i++)

s.writeObject(elementData[i]);

if (modCount != expectedModCount) {

throw new ConcurrentModificationException();

}

}

/**

* Reconstitute the <tt>ArrayList</tt> instance from a stream (that is,

* deserialize it).

*/

private void readObject(java.io.ObjectInputStream s)

throws java.io.IOException, ClassNotFoundException {

// Read in size, and any hidden stuff

s.defaultReadObject();

// Read in array length and allocate array

int arrayLength = s.readInt();

Object[] a = elementData = new Object[arrayLength];

// Read in all elements in the proper order.

for (int i = 0; i < size; i++)

a[i] = s.readObject();

}

ArrayList的构造器:

/**

* 创建一个对象数组,容量为initialCapacity,

*/

public ArrayList(int initialCapacity) {

super();

AbstractList() {}

if (initialCapacity < 0)

throw new IllegalArgumentException("Illegal Capacity:" + initialCapacity);

this.elementData = new Object[initialCapacity];

}

/**

* 默认初始化一个容量为10的对象数组

*/

public ArrayList() {

this(10);

}

当执行new ArrayList<String>()时,会调用上边的无参构造器,创造一个容量为10的对象数组。

在我们执行new ArrayList<String>(4)时,会调用上边的public ArrayList(int initialCapacity),创造一个容量为4的对象数组。

在实际使用中,如果是成员变量可以确定的场景,建议直接初始化时定好容量。

ArrayList扩容

/**

* 确保数组的容量足够,若是不够,必须扩容

*/

public void ensureCapacity(int minCapacity) {

modCount++;

int oldCapacity = elementData.length;//获取数组的容量

//容量满的情况下

if (minCapacity > oldCapacity) {

Object oldData[] = elementData;

int newCapacity = (oldCapacity * 3) / 2 + 1;//新容量为旧容量的1.5倍+1

if (newCapacity < minCapacity)//如果扩容后的新容量还不满足新增要求

newCapacity = minCapacity;//新容量设为预期需要的容量

elementData = Arrays.copyOf(elementData, newCapacity);//复制元素并使用新的容量大小

}

}

在上述代码的扩容结束后,调用了Arrays.copyOf(elementData, newCapacity)方法,这个方法先创建了一个新的容量为newCapacity的对象数组,然后使用System.arraycopy()方法将旧的对象数组复制到新的对象数组中去了。

注意:

modCount变量用于在遍历集合(iterator())时,检测是否发生了add、remove操作。

删除ArrayList中的对象

remove(Object o)需要遍历数组,remove(int index)不需要,只需要判断索引符合范围即可,所以,通常:后者效率更高。

遍历ArrayList中的对象(iterator方式)

源代码:iterator()方法是在内部类AbstractList中实现的,该方法返回AbstractList的一个内部类Itr对象

public Iterator<E> iterator() {

return new Itr();//返回一个内部类对象

}

Itr内部类:

private class Itr implements Iterator<E> {

int cursor = 0;//标记遍历到的元素位置

int expectedModCount = modCount;

//ArrayList修改次数,用于fast fail机制快速失败 原理详见HashMap篇

//检测对象数组是否还有元素

public boolean hasNext() {

return cursor != size();//如果cursor==size,表示遍历结束

}

//获取下一元素

public E next() {

checkForComodification();//检测在遍历的过程中,ArrayList是否发生了内容变化

try {

E next = get(cursor++);

return next;

} catch (IndexOutOfBoundsException e) {

checkForComodification();

throw new NoSuchElementException();

}

}

//检测在遍历的过程中,是否发生内容变化

final void checkForComodification() {

if (modCount != expectedModCount)//预期修改次数是否等于真的修改次数

throw new ConcurrentModificationException();

}

}

ArrayList基于数组方式实现,容量限制几乎无限

ArrayList线程不安全

最近发表
标签列表