java list 之详解_Java高级技术之List详解

List

List是一种有序的Collection,使用此接口能够精确地控制每个元素插入的位置。用户能够使用索引来访问List中的元素,每个元素的索引是固定的,我们可以认为List是一种动态的数组。

实现List接口的常用类有LinkedList,ArrayList,Vector和Stack.

ArrayList

ArrayList的底层实现原理是开辟出一块数组区域,能够加入任何类型的元素,包括null.ArrayList的size(),isEmpty(),get(),set()方法运行时间为常数。但是使用add()方法添加n个元素需要O(n)的时间,其他的方法运行时间为线性。

也就是说,使用ArrayList是要求随机读取的场景,因为Array在随机读取的时候效率很高,但是在频繁插入和删除的场景中,效率就会相对差一些。

ArrayList的部分核心JDK源码是这样的:

//增加

public void add(int index, E element) {

rangeCheckForAdd(index);

ensureCapacityInternal(size + 1); // Increments modCount!!

System.arraycopy(elementData, index, elementData, index + 1,size - index);

elementData[index] = element;

size++;

}

public boolean addAll(Collection c) {

Object[] a = c.toArray();

int numNew = a.length;

ensureCapacityInternal(size + numNew); // Increments modCount

System.arraycopy(a, 0, elementData, size, numNew);

size += numNew;

return numNew != 0;

}

//删除

public E remove(int index) {

rangeCheck(index);

modCount++;

E oldValue = elementData(index);

int numMoved = size - index - 1;

if (numMoved > 0)

System.arraycopy(elementData, index+1, elementData, index,

numMoved);

elementData[--size] = null; // clear to let GC do its work

return oldValue;

}

//查询

public E get(int index) {

rangeCheck(index);

return elementData(index);

}

//修改

public E set(int index, E element) {

rangeCheck(index);

E oldValue = elementData(index);

elementData[index] = element;

return oldValue;

}

其中,elementData是一个Object类型的数组,用于存储元素。当添加元素的时候,需要先判断elementData数组的长度,然后为其扩容,扩容的核心函数是grow(),其源代码是:

private void grow(int minCapacity) {

// overflow-conscious code

int oldCapacity = elementData.length;

int newCapacity = oldCapacity + (oldCapacity >> 1);

if (newCapacity - minCapacity

newCapacity = minCapacity;

if (newCapacity - MAX_ARRAY_SIZE > 0)

newCapacity = hugeCapacity(minCapacity);

// minCapacity is usually close to size, so this is a win:

elementData = Arrays.copyOf(elementData, newCapacity);

}

LinkedList

LinkedList与ArrayList类似,都类似于动态数组。与ArrayList的区别在于,LinkedList的底层数据结构是链表,这使得其在增加和删除某个元素的时候速度很快,是一个常数的复杂度,但是,在随机读取某个元素的时候,效率就会比较差,因为游标需要移动。所以,在大量增加和删除元素的时候,我们可以使用LinkedList,需要随机读取元素的时候,选用ArrayList.

此外LinkedList提供额外的get(),remove(),insert()方法在 LinkedList的首部或尾部。这些操作使LinkedList可被用作堆栈(stack),队列(queue)或双向队列(deque)。

它的JDK实现源代码是:

transient int size = 0;

/**

* Pointer to first node.

* Invariant: (first == null && last == null) ||

* (first.prev == null && first.item != null)

*/

transient Node first;

/**

* Pointer to last node.

* Invariant: (first == null && last == null) ||

* (last.next == null && last.item != null)

*/

transient Node last;

//链表的数据结构

private static class Node {

E item;

Node next;

Node prev;

Node(Node prev, E element, Node next) {

this.item = element;

this.next = next;

this.prev = prev;

}

}

//添加元素

public void add(int index, E element) {

checkPositionIndex(index);

if (index == size)

linkLast(element);

else

linkBefore(element, node(index));

}

/**

* Links e as first element.

*/

private void linkFirst(E e) {

final Node f = first;

final Node newNode = new Node(null, e, f);

first = newNode;

if (f == null)

last = newNode;

else

f.prev = newNode;

size++;

modCount++;

}

/**

* Links e as last element.

*/

void linkLast(E e) {

final Node l = last;

final Node newNode = new Node(l, e, null);

last = newNode;

if (l == null)

first = newNode;

else

l.next = newNode;

size++;

modCount++;

}

//删除

public void remove() {

checkForComodification();

if (lastReturned == null)

throw new IllegalStateException();

Node lastNext = lastReturned.next;

unlink(lastReturned);

if (next == lastReturned)

next = lastNext;

else

nextIndex--;

lastReturned = null;

expectedModCount++;

}

//查询

public E get(int index) {

checkElementIndex(index);

return node(index).item;

}

//修改

public E set(int index, E element) {

checkElementIndex(index);

Node x = node(index);

E oldVal = x.item;

x.item = element;

return oldVal;

}

Vector & Stack

Vector与ArrayList很类似,区别是Vector的方法是同步的,这些方法被加上synchronized关键字修饰,这将在后面的高并发中具体阐述。

由Vector创建的Iterator,虽然和ArrayList创建的Iterator实现的同一接口,但是,由于Vector是同步的,当一个Iterator被创建而且正在被使用,另一个线程改变了Vector的状态(如添加或删除了一些元素),这时调用Iterator的方法时将抛出 ConcurrentModificationException异常,需要手动去捕获该异常。

Stack类继承自Vector,实现的是一个堆栈的数据结构。Stack提供5个额外的方法使得Vector可以被当作堆栈使用。这五个额外的方法分别是:push()和pop()方法入栈和出栈,peek()方法用于得到栈顶的元素,empty()方法测试堆栈是否为空,search()方法检测某元素在堆栈中的位置。Stack刚创建后是元素是空的。

Stack继承自Vector,自然也是由synchronized修饰过的同步容器。而除了这两个类,其他实现List接口的容器类并没有实现同步,在多线程场景下需要注意线程安全问题。有关同步容器,将在后面的高并发中具体涉及到。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值