您的位置:首页 > 编程语言 > Java开发

Java容器学习之——List

2016-02-26 14:16 471 查看
下面学习一下Java中的List结构。



在List家族中,我们主要使用的就是LinkedList,ArrayList,和Vector三个主要的容器。


一、LinkedList和ArrayList的区别

从上面的继承图上来看,ArrayList只是实现了List接口,而LinkedList则是实现了List和Deque两个接口。LinkedList的本质是一个双向链表。也可以把它当成为队列使用,还可以当成为栈来使用(Deque代表双端队列,也就是说可以对队列的双端进行操作。)

对于ArrayList来说,其底层使用的是数组。这样子,如果我们需要在特定的位置添加数据的话就需要移动大量的数据,并且还有可能会面临扩容的情况,这个时候就性能就不够好了。但是对于获得index的元素的话则性能是相当好的。

对于LinkedList来说我对于特定的插入情况下,我们可以判断是应该从链表的表头开始还是从表尾开始遍历。然后找到元素后就将其插入,这个时候插入的系统开销是会比ArrayLsit小一些的。但是对于要获得index位置的元素的话则性能就比ArrayList差的多了。

ArrayList 和 LinkedList的适用场景

     总的来说ArrayList的性能是优于LinkedList,适用的场景也是比较多。但是当我们需要执行大量的add 或者对头和尾进行许多操作。并且对于get(index)方法的执行次数不高的话。则可以适用LinkedList,其他情况则使用ArrayList比较好。


二、ArrayList与Vector


1、序列化差异


ArrayList和Vector这两个集合类本质上没有太大的不同,他们都是实现了List接口。并且都是用来保存底层的java数组的。但是我们看看其中对于数组这一块的定义。

Vector:

protected Object[] elementData;


ArrayList:

transient Object[] elementData; /


这说明了ArrayList中的数据集合是不能够直接被序列化的。而ArrayList中提供了writeObjec
4000
t readObject两个方法来定制序列化。

而Vector是直接可以序列化的,并且它只是提供了writeObject方法而已,所以并不能够定制序列化。
从序列化的角度来看ArrayList比Vector更加安全,因为其提供了自定义序列化方式,所以不会很容易被人家解密。

2、线程安全

除此之外就是Vector中每一个方法都有synchronized 修饰,所以我们可以将Vector当成为ArrayList的线程安全版本。

3、空间扩容

对于ArrayList的构造方法来说,其可以传递一个初始的大小,如果空间不足的话就可以按照原来的1.5倍扩充容量。

public ArrayList(int initialCapacity)


而对于Vector来说,除了我们可以指定空间大小之外我们还可以指定增长的大小。也就是每次扩容的时候容量就会增加capacityIncrement,如果我们将增长大小指定为0的话则增长的情况就与ArrayList一样,空间不足的时候就会扩容1.5倍。

public Vector(int initialCapacity, int capacityIncrement)


4、比较&选择

由上面我们可以知道ArrayList不仅是序列化安全的,同时可用性等都会比Vector好。ArrayLsit已经基本替代了Vector了。而Vector的唯一有点就是线程安全。而我们也可以通过Collections工具类的synchronizedList方法得到一个线程安全的ArrayList

public static <T> List<T> synchronizedList(List<T> list) {
return (list instanceof RandomAccess ?
new SynchronizedRandomAccessList<>(list) :
new SynchronizedList<>(list));
}


我们可以看到这个提供线程安全的ArrayList的方法其实就是通过原有的数据来生成一个线程安全的ArrayList。

static class SynchronizedList<E>
extends SynchronizedCollection<E>
implements List<E> {
private static final long serialVersionUID = -7754090372962971524L;
 
final List<E> list;
 
SynchronizedList(List<E> list) {
super(list);
this.list = list;
}
SynchronizedList(List<E> list, Object mutex) {
super(list, mutex);
this.list = list;
}
 
public boolean equals(Object o) {
if (this == o)
return true;
synchronized (mutex) {return list.equals(o);}
}
public int hashCode() {
synchronized (mutex) {return list.hashCode();}
}
 
public E get(int index) {
synchronized (mutex) {return list.get(index);}
}
public E set(int index, E element) {
synchronized (mutex) {return list.set(index, element);}
}
public void add(int index, E element) {
synchronized (mutex) {list.add(index, element);}
}
public E remove(int index) {
synchronized (mutex) {return list.remove(index);}
}
 
public int indexOf(Object o) {
synchronized (mutex) {return list.indexOf(o);}
}
public int lastIndexOf(Object o) {
synchronized (mutex) {return list.lastIndexOf(o);}
}
 
public boolean addAll(int index, Collection<? extends E> c) {
synchronized (mutex) {return list.addAll(index, c);}
}
 
public ListIterator<E> listIterator() {
return list.listIterator(); // Must be manually synched by user
}
 
public ListIterator<E> listIterator(int index) {
return list.listIterator(index); // Must be manually synched by user
}
 
public List<E> subList(int fromIndex, int toIndex) {
synchronized (mutex) {
return new SynchronizedList<>(list.subList(fromIndex, toIndex),
mutex);
}
}
 
@Override
public void replaceAll(UnaryOperator<E> operator) {
synchronized (mutex) {list.replaceAll(operator);}
}
@Override
public void sort(Comparator<? super E> c) {
synchronized (mutex) {list.sort(c);}
}

 
private Object readResolve() {
return (list instanceof RandomAccess
? new SynchronizedRandomAccessList<>(list)
: this);
}
}


我们可以看到其中所谓的线程安全ArrayList就是实现了Lis接口,并且将所有的操作都变成一个互斥的信号量来控制。也就能够确保线程安全了。

三、Stack

另外还有基于Vector的Stack。

我们会发现Stack只是在Vector上面添加了5个栈操作的方法而已。其本质上还是一个Vector。并且我们可以看到Stack中的每一个方法都有synchronized 修饰,因为Vector是线程安全的,所以Stack也是线程安全的。

实际上即使程序需要使用栈这种数据结构的话java也不再推荐使用Stack,而是推荐实现了Deque接口的ArrayDeque来替代Stack。
但只是在无需保证线程安全的情况下才推荐使用。因为自带的Stack是考虑到线程安全的,所以我们在对线程安全不要求的情况下其性能是比较差的。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  java arraylist linkedlist