Java中List的简述
Posted 努力创造BUG
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java中List的简述相关的知识,希望对你有一定的参考价值。
快速通道
什么是 List
什么是集合
集合就是把具有相同属性的东西放在一起,也可以是容器,把有关的东西都放进去
什么是 List
List是位于java.util下的一个接口,有序集合(也称为序列)。此界面的用户可以精确控制每个元素在列表中的插入位置。用户可以通过整数索引(列表中的位置)访问元素,并在列表中搜索元素
List的继承、实现关系
其继承了Collection接口并由AbstractList来实现,Collection又继承了Iterable接口
- Collection:集合层次结构中的根接口。一个集合表示一组对象,称为它的元素。一些集合允许重复元素,而另一些则不允许。有些是有序的,有些是无序的。
- Iterable:实现此接口允许对象成为“for-each 循环”语句的目标。
List类的位置
jre\\lib\\rt.jar\\java\\util 下
也就是java本身自带的,不需要额外引用jar来实现
List的种类
- ArrayList:底层由数组结构实现Object[],可以存储任何Object类型的对象,是非线程安全的
- LinkedList:List和Deque接口的双向链表实现。实现所有可选列表操作,并允许所有元素(包括null )。所有操作都按照双向链表的预期执行。索引到列表中的操作将从开头或结尾遍历列表,以更接近指定索引的为准。
- Vector:底层实现是动态数组的方式存放数据,是线程安全的,Vector源码当中每个方法都被synchronized关键字进行修饰,保证了Vector的线程安全,所以效率很低,尽量少使用
ArrayList
使用
List list = new ArrayList<>();
List<Object> list1= new ArrayList<>();
List<Map> list2= new ArrayList<>();
List<Student> list3= new ArrayList<>();
List<Object> list4 = new ArrayList<>(2);
List<Object> list5 = new ArrayList<>(list);
...
实现方式
创建对象的时候会调用其无参构造方法
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = ;
/**
* The array buffer into which the elements of the ArrayList are stored.
* The capacity of the ArrayList is the length of this array buffer. Any
* empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
* will be expanded to DEFAULT_CAPACITY when the first element is added.
*/
transient Object[] elementData; // non-private to simplify nested class access
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList()
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
/**
* Constructs an empty list with the specified initial capacity.
*
* @param initialCapacity the initial capacity of the list
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public ArrayList(int initialCapacity)
if (initialCapacity > 0)
this.elementData = new Object[initialCapacity];
else if (initialCapacity == 0)
this.elementData = EMPTY_ELEMENTDATA;
else
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public ArrayList(Collection<? extends E> c)
Object[] a = c.toArray();
if ((size = a.length) != 0)
if (c.getClass() == ArrayList.class)
elementData = a;
else
elementData = Arrays.copyOf(a, size, Object[].class);
else
// replace with empty array.
elementData = EMPTY_ELEMENTDATA;
可见,当创建ArrayList对象的时候就会创建好一个初始容量为 10 的空列表等待着被使用。
如何扩容
private void ensureExplicitCapacity(int minCapacity)
modCount++;
// overflow-conscious code
if (minCapacity - elementData.length > 0)
grow(minCapacity);
/**
* Increases the capacity to ensure that it can hold at least the
* number of elements specified by the minimum capacity argument.
*
* @param minCapacity the desired minimum capacity
*/
private void grow(int minCapacity)
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
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);
int newCapacity = oldCapacity + (oldCapacity >> 1);
每次自增一半,即原来的1.5倍
LinkedList
使用
List list = new LinkedList<>();
List<Object> list1 = new LinkedList<>();
List<Map> list2 = new LinkedList<>();
List<Student> list3 = new LinkedList<>();
List<Object> list4 = new LinkedList<>(list);
...
实现方式
创建对象的时候会调用其无参构造方法
/**
* Constructs an empty list.
*/
public LinkedList()
/**
* Constructs a list containing the elements of the specified
* collection, in the order they are returned by the collection's
* iterator.
*
* @param c the collection whose elements are to be placed into this list
* @throws NullPointerException if the specified collection is null
*/
public LinkedList(Collection<? extends E> c)
this();
addAll(c);
/**
* Appends all of the elements in the specified collection to the end of
* this list, in the order that they are returned by the specified
* collection's iterator. The behavior of this operation is undefined if
* the specified collection is modified while the operation is in
* progress. (Note that this will occur if the specified collection is
* this list, and it's nonempty.)
*
* @param c collection containing elements to be added to this list
* @return @code true if this list changed as a result of the call
* @throws NullPointerException if the specified collection is null
*/
public boolean addAll(Collection<? extends E> c)
return addAll(size, c);
LinkedList初始化为空
如何扩容
由于LinkedList使用双向列表实现的其结构为
private static class Node<E>
E item;
Node<E> next;
Node<E> prev;
Node(Node<E> prev, E element, Node<E> next)
this.item = element;
this.next = next;
this.prev = prev;
因此也没有扩容的机制,如有需求一直在其前面或者后面新增下去
Vector
使用
Vector vector = new Vector<>();
Vector<Object> vector1 = new Vector<>();
Vector<Map> vector2 = new Vector<>();
Vector<Student> vector3 = new Vector<>();
...
实现方式
/**
* The array buffer into which the components of the vector are
* stored. The capacity of the vector is the length of this array buffer,
* and is at least large enough to contain all the vector's elements.
*
* <p>Any array elements following the last element in the Vector are null.
*
* @serial
*/
protected Object[] elementData;
/**
* The amount by which the capacity of the vector is automatically
* incremented when its size becomes greater than its capacity. If
* the capacity increment is less than or equal to zero, the capacity
* of the vector is doubled each time it needs to grow.
*
* @serial
*/
protected int capacityIncrement;
/**
* Constructs an empty vector so that its internal data array
* has size @code 10 and its standard capacity increment is
* zero.
*/
public Vector()
this(10);
/**
* Constructs an empty vector with the specified initial capacity and
* with its capacity increment equal to zero.
*
* @param initialCapacity the initial capacity of the vector
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public Vector(int initialCapacity)
this(initialCapacity, 0);
/**
* Constructs an empty vector with the specified initial capacity and
* capacity increment.
*
* @param initialCapacity the initial capacity of the vector
* @param capacityIncrement the amount by which the capacity is
* increased when the vector overflows
* @throws IllegalArgumentException if the specified initial capacity
* is negative
*/
public Vector(int initialCapacity, int capacityIncrement)
super();
if (initialCapacity < 0)
throw new IllegalArgumentException("Illegal Capacity: "+
initialCapacity);
this.elementData = new Object[initialCapacity];
this.capacityIncrement = capacityIncrement;
可以看出Vector和ArrayList是非常相似的
- 都是一个Object[]类型存储数据
- 无参数构造默认数组容量是10
- 使用有参数的构造方法可以指定容量的大小
如何扩容
private void grow(int minCapacity)
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
capacityIncrement : oldCapacity);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
int newCapacity = oldCapacity + ((capacityIncrement > 0) ? capacityIncrement : oldCapacity);
每次自增一倍,即原来的2倍
常用方法
共有
- int size();
返回此列表中的元素数 - boolean isEmpty();
如果此列表不包含任何元素,则返回true - boolean contains(Object o);
如果此列表包含指定元素,则返回true - Iterator iterator();
以正确的顺序返回此列表中元素的迭代器 - Object[] toArray();
返回此列表中从第一个元素到最后一个元素的数组 - boolean add(E e);
将指定元素附加到此列表的末尾 - boolean remove(Object o);
如果指定元素存在,则从该列表中删除第一次出现的指定元素。如果此列表不包含该元素,则它不变 - boolean addAll(Collection<? extends E> c);
将指定集合中的所有元素附加到此列表的末尾,按照指定集合的迭代器返回的顺序 - boolean removeAll(Collection<?> c);
从此列表中删除包含在指定集合中的所有元素 - void clear();
从此列表中删除所有元素。此调用返回后,列表将为空 - boolean equals(Object o);
比较指定对象与此列表是否相等。当且仅当指定对象也是一个列表时返回true ,两个列表具有相同的大小,并且两个列表中所有对应的元素对都相等 - E get(int index);
返回此列表中指定位置的元素 - E set(int index, E element);
将此列表中指定位置的元素替换为指定元素 - void add(int index, E element);
在此列表中的指定位置插入指定元素。将当前位于该位置的元素和任何后续元素向右移动 - E remove(int index);
移除此列表中指定位置的元素 - int indexOf(Object o);
返回此列表中指定元素第一次出现的索引,如果此列表不包含该元素,则返回 -1 - int lastIndexOf(Object o);
返回此列表中指定元素最后一次出现的索引,如果此列表不包含该元素,则返回 -1
LinkedList
- E getFirst();
返回此列表中的第一个元素 - E getLast();
返回此列表中的最后一个元素 - E removeFirst();
从此列表中删除并返回第一个元素 - E removeLast();
移除并返回此列表中的最后一个元素 - void addFirst(E e);
在此列表的开头插入指定元素 - void addLast(E e);
将指定元素附加到此列表的末尾 - boolean hasNext();
如果此列表迭代器在向前遍历列表时具有更多元素,则返回true - E next();
返回列表中的下一个元素并前进光标位置
结尾
- 上述内容绝大多数来自源码
- 部分为自己总结
记:反复使用后的小总结
java基础-容器简述
常用的容器有list、queue、set、map
list有ArrayList、LinkedList,还有一个CopyOnWriteArrayList;
queue有LinkedList、ArrayQueue、LinkedBlockingQueue、ConcurrentLinkedQueue;
map有HashMap、TreeMap、ConcurrentHashMap、ConcurrentSkipListMap;
set内部一般会使用map做存储,有HashSet、TreeSet、CopyOnWriteArraySet、ConcurrentSkipListSet;
之前介绍过ConcurrentHashMap,该map由于需要resize,所以需要锁机制,且加锁粒度较大;Blocking系列由于需要wait、notify操作,所以也需要锁机制;ConcurrentLinkedQueue则是完全的CAS操作。
List
ArrayList是一个数组,在插入元素可能涉及扩容、元素移动,在删除时可能涉及元素移动,如果只是在list尾部插入删除,就不会涉及元素移动,其优势在于随机访问。
LinkedList是一个链表,每次插入元素都会新建一个该元素的节点,然后放入链表中,与ArrayList相比,优势就在于插入、删除操作不会涉及元素移动,只涉及前后引用的改变,同样也不存在扩容问题,链表理论可以无限大(实际长度不能超过Integer.MAX_VALUE,且受限于jvm堆空间)。
CopyOnWriteArrayList是一个数组,与ArrayList不同之处在于,CopyOnWriteArrayList在更新操作前都会新建一个数组(该数组大小正好容下新旧元素),然后在新数组进行更新操作,最后再将旧数组替换掉,并且整个更新过程都是加锁的(ReentrantLock),即是线程安全的。可见,CopyOnWriteArrayList的更新操作的性能不是一般的差啊,但是其优势在于iterator是完全安全的,因为更新操作永远是在一个新数组上进行,而iterator操作永远都是旧数组,但也因为iterator操作的是旧数组,所以CopyOnWriteArrayList的iterator不提供更新操作(如remove)。
Queue
ArrayQueue比ArrayList要高效一些,因为其将更新元素操作限制在了数组的头尾,在插入删除时不再需要移动元素(插入时仍然会涉及扩容)。
LinkedList不仅实现了list接口,同样还实现了queue、deque(double ended queue)接口。
LinkedBlockingQueue提供了一个阻塞的双向队列,可以实现在队列为空、为满时等待,非空、非满时唤醒,这是通过ReentrantLock+Condition实现的,也就是说LinkedBlockingQueue是线程安全的(虽然LinkedBlockingQueue为链式结构,但其在构造器中提供了capacity的设置,默认capacity为Integer.MAX_VALUE)。
ConcurrentLinkedQueue提供了线程安全的队列实现,与LinkedBlockingQueue不同的是ConcurrentLinkedQueue并没有使用锁机制,使用的是CAS机制,这样可以极大提高并发性。
Map
HashMap的hash表是一个数组,解决hash冲突的方式是链表或红黑树(jdk8)。
TreeMap是一棵红黑树。
ConcurrentHashMap结构与HashMap类似,通过在桶上加锁实现了线程安全。
ConcurrentSkipListMap使用了跳表,跳表的物理结构为多层链表,逻辑结构是一棵树,与ConcurrentHashMap相比,ConcurrentSkipListMap的最大特点就是key有序。
Set
CopyOnWriteArraySet包装了CopyOnWriteArrayList,CopyOnWriteArraySet的add方法就是CopyOnWriteArrayList的addIfAbsent方法,同样是线程安全的。
以上是关于Java中List的简述的主要内容,如果未能解决你的问题,请参考以下文章