java arraycopy api,JAVA API备忘----集合

类继承关系图

a4c26d1e5885305701be709a3d33442f.png

List:List有两个实现类,ArrayList和LinkedList,前者用数组实现,后者用链表实现,关于两者的比较,将会在分析之后给出。

ArrayList:先来看看最常用的ArrayList,它继承了AbstractList,实现了List,

RandomAccess, Cloneable, Serializable四个接口。

常常听见ArrayList是用数组实现的,的确ArrayList中存储数据的结构就是一个对象数组,当new一个新的ArrayList,其实是new了一个长度为10(默认值)的对象数组。

其上的操作就是对数组的操作,只是更为简单而已。

public

ArrayList(int initialCapacity) {

super();

if (initialCapacity < 0)

throw new IllegalArgumentException("Illegal Capacity:

"+initialCapacity);

this.elementData = new Object[initialCapacity];

}

自动变长机制:

印象很深的是ArrayList数组好用多了,之所以有这样的感觉,全都是因为ArrayList能够自动变长,而数组则是定长的,自动变长在编写程序时是极为方便的。

那么ArrayList是怎样实现自动变长的呢?OK,让我们先来分析add()方法

public

boolean add(Object o) {

ensureCapacity(size + 1); // Increments

modCount!!

elementData[size++] = o;

return true;

}

可以看出,ensureCapacity()方法主要用来保证新增元素后不会越界,下面来看ensureCapacity

public

void ensureCapacity(int minCapacity) {

modCount++;

int oldCapacity = elementData.length;

if (minCapacity > oldCapacity) {

Object

oldData[] = elementData;

int newCapacity = (oldCapacity * 3)/2 + 1;

if (newCapacity < minCapacity)

newCapacity = minCapacity;

elementData = new Object[newCapacity];

System.arraycopy(oldData, 0, elementData, 0, size);

}

}

此时就能看出自动变长是如何实现的了。当数组容量不够时先new一个新的数组,长度是原来的3/2,然后用System.arraycopy方法将数据从老数组copy到新数组,

由此可知,在改变数组长度时是需要开销的,就是说,变长是需要代价的。

迭代器: 使用List的迭代器时一定有所体会,当运行类似如下程序时,会抛出一个ConcurrentModificationException

Iterator iterator = list.iterator();

while(iterator.hasNext())

{

set.remove(iterator.next());

}

关于这点,JDK又是怎样实现的呢?思想就是将iterator看成一个“临界区”,只是不是多线程而是单个线程内部的“临界”。这里借助于一个modCount,定义如下:

protected transient int modCount = 0;

在迭代过程中不允许修改原始list的方法中(如add,remove)每次对modCount自增1,比如add方法中通过ensureCapacity方法让modCount++,而在调用迭代器时(实际

上是初始化迭代器时)将modCount赋值给expectedModCount

int expectedModCount = modCount;

每次调用迭代器的next()方法就会进行checkForComodification()检查是否expectedModCount已经不等于modCount,如果不等,说明在迭代过程中已经通过remove()或add()等方法对原集合进行过修改,这是不允许的,所以checkForComodification()抛出ConcurrentModificationException异常;如果相等,说明迭代过程中集合没有被修改过。

为什么需要保证迭代中集合不能被修改呢?因为这样就不能保证集合能够被完全遍历到,因此,java的开发人员使用了这个比较巧妙的方法来解决这个问题。

public Object next() {

try {

Object next = get(cursor);

checkForComodification();

lastRet = cursor++;

return next;

} catch(IndexOutOfBoundsException e) {

checkForComodification();

throw new NoSuchElementException();

}

}

final void

checkForComodification() {

if (modCount != expectedModCount)

throw new ConcurrentModificationException();

}

序列化:

ArrayList中最奇怪的就要数

private transient Object elementData[];

中transient标志了,序列化最主要的目的就是将这个对象数组序列化,可偏偏它却加上了transient关键字阻止它的序列化,真是令人费解。

查了些资料才知道,elementData中存放的都是对象的引用而不是真实对象,这就是说即使序列化也不能达到我们预想的效果,当你反序列化时这些引用已经不指向原来的对象了,因此多了两个方法writeObject()和readObject()进行手工序列化或反序列化。

private

synchronized void writeObject (java.io.ObjectOutputStream s)

throws java.io.IOException{

// Write out element count, and any hidden stuff

s.defaultWriteObject();

// Write out array length

s.writeInt(elementData.length);

// Write out all elements in the proper order.

for

(int i=0; i

s.writeObject(elementData[i]);

}

private

synchronized 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();

elementData = new Object[arrayLength];

// Read in all elements in the proper order.

for (int i=0; i

elementData[i] = s.readObject();

}

LinkedList:

LinkedList的实现类似数据结构中的双向链表,每个结点是这样一个结构:

private

static class Entry {

Object element;

Entry next;

Entry previous; }

构造一个带头节点的指针,请注意,这个链表是循环双向的,因此从头指针可以很容易找到尾节点。

private transient Entry header = new Entry(null,

null, null);

LinkedList实现了一些特有的方法,比如getFirst(),getLast(),addFirst(),addLast(),removeFirst(),removeLast(),看到这个立马就想到队列,yes,完全正确,当你需要实现自己的queue时,LinkedList可是比较好的选择。

比较下ArrayList、LinkedList、Vector:

正如数组和链表的优劣一样,承袭了二者的ArrayList和LinkedList也是各有优劣。

ArrayList适合查找,快速定位,一般需要使用变长的数组就非他莫数了。

LinkedList适合频繁插入、删除,尤其是在表头尾的插入删除操作。

Vector中,非常类似ArrayList,但是其中加入了同步锁,不同步的时候使用它是会降低效率的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值