集合

框架关系图:

Collection接口下面有三个子接口:List、Set、Queue。此篇是关于List<E>的简单学习总结。

补充:HashTable父类是Dictionary,不是AbstractMap。

List(有序、可重复):

List里存放的对象是有序的,同时也是可以重复的,List关注的是索引,拥有一系列和索引相关的方法,查询速度快。因为往list集合里插入或删除数据时,会伴随着后面数据的移动,所有插入删除数据速度慢。

List常用的子类:ArrayList。(面试常问的:Vector、ArrayList、LinkedList之间的区别)。

ArrayList:

public class ArrayList<E> extends AbstractList<E> implements List<E> (继承AbstractList类,实现List接口)

  • 方法摘要(标黄为常用方法)

    Modifier and Type 方法 描述
    void add​(int index, E element)
    在此列表中的指定位置插入指定的元素。
    boolean add​(E e)
    将指定的元素追加到此列表的末尾。
    boolean addAll​(int index, Collection<? extends E> c)
    将指定集合中的所有元素插入到此列表中,从指定的位置开始。
    boolean addAll​(Collection<? extends E> c)
    按指定集合的Iterator返回的顺序将指定集合中的所有元素追加到此列表的末尾。
    void clear​()
    从列表中删除所有元素。
    Object clone​()
    返回此 ArrayList实例的浅拷贝。
    boolean contains​(Object o)
    如果此列表包含指定的元素,则返回 true
    void ensureCapacity​(int minCapacity)
    如果需要,增加此 ArrayList实例的容量,以确保它至少能够容纳最小容量参数指定的元素数量。
    void forEach​(Consumer<? super E> action)
    Iterable每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。
    E get​(int index)
    返回此列表中指定位置的元素。
    int indexOf​(Object o)
    返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
    boolean isEmpty​()
    如果此列表不包含元素,则返回 true
    Iterator<E> iterator​()
    以正确的顺序返回该列表中的元素的迭代器。
    int lastIndexOf​(Object o)
    返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
    ListIterator<E> listIterator​()
    返回列表中的列表迭代器(按适当的顺序)。
    ListIterator<E> listIterator​(int index)
    从列表中的指定位置开始,返回列表中的元素(按正确顺序)的列表迭代器。
    E remove​(int index)
    删除该列表中指定位置的元素。
    boolean remove​(Object o)
    从列表中删除指定元素的第一个出现(如果存在)。
    boolean removeAll​(Collection<?> c)
    从此列表中删除指定集合中包含的所有元素。
    boolean removeIf​(Predicate<? super E> filter)
    删除满足给定谓词的此集合的所有元素。
    protected void removeRange​(int fromIndex, int toIndex)
    从此列表中删除所有索引为 fromIndex (包括)和 toIndex之间的元素。
    void replaceAll​(UnaryOperator<E> operator)
    将该列表的每个元素替换为将该运算符应用于该元素的结果。
    boolean retainAll​(Collection<?> c)
    仅保留此列表中包含在指定集合中的元素。
    E set​(int index, E element)
    用指定的元素替换此列表中指定位置的元素。
    int size​()
    返回此列表中的元素数。
    void sort​(Comparator<? super E> c)
    根据指定的Comparator引发的顺序排列此列表。
    Spliterator<E> spliterator​()
    在此列表中的元素上创建late-binding故障快速 Spliterator
    List<E> subList​(int fromIndex, int toIndex)
    返回指定的 fromIndex (含)和 toIndex之间的列表部分的视图。
    Object[] toArray​()
    以正确的顺序(从第一个到最后一个元素)返回一个包含此列表中所有元素的数组。
    <T> T[] toArray​(T[] a)
    以正确的顺序返回一个包含此列表中所有元素的数组(从第一个到最后一个元素); 返回的数组的运行时类型是指定数组的运行时类型。
    void trimToSize​()
    修改这个 ArrayList实例的容量是列表的当前大小。 

用法:

     public static void main(String[] args) {
ArrayList<String> list = new ArrayList<String>();
System.out.println(list.isEmpty());// 方法:isEmpty​(),如果此列表不包含元素,则返回 true。
list.add(0, "A");// 方法:add​(int index, E element),在此列表中的指定位置插入指定的元素。给第一个位置加元素:A
list.add(1, "B");// 给第二个位置加元素:B
list.add("C");//方法:add​(E e), 将指定的元素追加到此列表的末尾。 继续追加元素:C
list.add("D");//继续追加元素:D
// 此时遍历一下,看看list的值是否成功加入。
for (String value : list) {// 方法:forEach​(Consumer<? super E> action),对Iterable每个元素执行给定的操作,直到所有元素都被处理或动作引发异常。注意:此时使用Iterator迭代器遍历数值。
System.out.println(value);//输出:A B C D,成功加入数值
}
System.out.println(list.size());//方法:size​() 返回此列表中的元素数。
System.out.println(list.isEmpty());// 此时再用方法判断一下,因为已经有值所以返回False
System.out.println(list.contains("A"));// 方法:contains​(Object o),如果此列表包含指定的元素,则返回 true 。
System.out.println(list.get(2));// 方法: get​(int index) 返回此列表中指定位置的元素。
System.out.println(list.indexOf("B"));// 方法:indexOf​(Object o) 返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
System.out.println(list.indexOf("E"));// 此时返回:-1
System.out.println("--------分割线--------");
list.remove(2);// 方法:remove​(int index) 删除该列表中指定位置的元素。
// 此时遍历一下,看看list的值是否成功删除。
for (String value : list) {
System.out.println(value);
}
System.out.println("--------分割线--------");
list.remove("D");// 方法:remove​(Object o) 从列表中删除指定元素的第一个出现(如果存在)。
// 此时遍历一下,看看list的值是否成功删除。
/*注意List中的remove方法不能和foreach()连用,因为foreach使用Iterator迭代,和list中的方法无法识别,
如果用list.remove()删除元素,会导致list数值和长度大小都发生改变,但此时Iterator无法知道此时,于是就会报错:ConcurrentModificationException*/
for (String value : list) {
System.out.println(value);
}
System.out.println("--------分割线--------");
//为了后面演示方法,此时再假如几个值
list.add("C");
list.add("D");
list.add("e");
for (String value : list) {
System.out.println(value);
}
System.out.println("--------分割线--------");
list.set(4, "E");
for (String value : list) {
System.out.println(value);
}
}

补充一:ArrayList底层其实是动态数组,长度可变,源代码如下:

 private static final Object[] EMPTY_ELEMENTDATA = {};
public boolean add(E e) {
ensureCapacityInternal(size + 1); // Increments modCount!!
elementData[size++] = e;
return true;
}
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++;
}

补充二:ArrayList初始容量是:10,超过这个容量会扩容,扩容规则为:数组需要最小容量+(数组需要最小容量/2),即扩容 1.5倍,源代码如下:

     private static final int DEFAULT_CAPACITY = 10;
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
} ensureExplicitCapacity(minCapacity);
}
private void ensureExplicitCapacity(int minCapacity) {
modCount++; if (minCapacity - elementData.length > 0)
grow(minCapacity);
}
private void grow(int minCapacity) {
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
elementData = Arrays.copyOf(elementData, newCapacity);
}

ArrayList、Vector、LinkedList:

Linkedlist:

Linkedlist和ArrayList、Vector不一样的地方是,Linkedlist不是采用数组结构,而是链状结构,着重操作首位元素和末位元素,源代码如下:

     transient Node<E> first;
transient Node<E> last; public void addFirst(E e) {
linkFirst(e);
}
private void linkFirst(E e) {
final Node<E> f = first;
final Node<E> newNode = new Node<>(null, e, f);
first = newNode;
if (f == null)
last = newNode;
else
f.prev = newNode;
size++;
modCount++;
}
public void addLast(E e) {
linkLast(e);
}
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}

因为LinkedList着重操作首尾元素,所以增和删相对来说比较高效,而ArrayList和Vector底层是动态数组,存在数组索引(index),所以改和查比较高效。

Vector(已过期,基本不再使用):

Vector和ArrayList,LinkedList不同的地方是,Vector是线程安全的List,因为它源代码中的方法基本都加上了关键词synchronized:

     public synchronized void addElement(E obj) {
modCount++;
ensureCapacityHelper(elementCount + 1);
elementData[elementCount++] = obj;
}
public synchronized void insertElementAt(E obj, int index) {
modCount++;
if (index > elementCount) {
throw new ArrayIndexOutOfBoundsException(index
+ " > " + elementCount);
}
ensureCapacityHelper(elementCount + 1);
System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
elementData[index] = obj;
elementCount++;
}
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
public synchronized E set(int index, E element) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index); E oldValue = elementData(index);
elementData[index] = element;
return oldValue;
}
public synchronized E get(int index) {
if (index >= elementCount)
throw new ArrayIndexOutOfBoundsException(index); return elementData(index);
}

有没有其他线程安全的List?

1、java.util.Collections.SynchronizedList

        public static <T> List<T> synchronizedList (List < T > list) {
return (list instanceof RandomAccess ? new SynchronizedRandomAccessList<>(list) : new SynchronizedList<>(list));
}
SynchronizedList(List < E > list) {
super(list);
this.list = list;
}
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);
}
}

1、Collection是集合的根接口,Collections是一个Java.util 包下的工具类。

2、Collections.synchronizedList返回的List和Vector一样,在方法上都有synchronized关键字加了锁,让线程变得安全,但同时性能会下降。

2、CopyOnWriteArrayList

CopyOnWriteArrayList是Java1.5加入的一个线程安全的变体ArrayList ,其中所有可变操作( add , set ,等等)通过对底层数组的最新副本实现。实现方法是:先复制一份List,然后上锁,然后进行增删改查的操作,操作过后再解锁。

     private transient volatile Object[] array;
final Object[] getArray () {
return array;
}
public CopyOnWriteArrayList() {
setArray(new Object[0]);
}
public CopyOnWriteArrayList(E[]toCopyIn){
setArray(Arrays.copyOf(toCopyIn, toCopyIn.length, Object[].class));
}
public boolean add (E e){
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len + 1);
newElements[len] = e;
setArray(newElements);
return true;
} finally {
lock.unlock();
}
}
public E set ( int index, E element){
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
E oldValue = get(elements, index); if (oldValue != element) {
int len = elements.length;
Object[] newElements = Arrays.copyOf(elements, len);
newElements[index] = element;
setArray(newElements);
} else {
// Not quite a no-op; ensures volatile write semantics
setArray(elements);
}
return oldValue;
} finally {
lock.unlock();
}
}
public E remove ( int index){
final ReentrantLock lock = this.lock;
lock.lock();
try {
Object[] elements = getArray();
int len = elements.length;
E oldValue = get(elements, index);
int numMoved = len - index - 1;
if (numMoved == 0)
setArray(Arrays.copyOf(elements, len - 1));
else {
Object[] newElements = new Object[len - 1];
System.arraycopy(elements, 0, newElements, 0, index);
System.arraycopy(elements, index + 1, newElements, index,
numMoved);
setArray(newElements);
}
return oldValue;
} finally {
lock.unlock();
}
}
public E get ( int index){
final ReentrantLock lock = l.lock;
lock.lock();
try {
rangeCheck(index);
checkForComodification();
return l.get(index + offset);
} finally {
lock.unlock();
}
}

数据结构(集合)学习之List的更多相关文章

  1. 数据结构(集合)学习之Map(一)

    集合 框架关系图: 补充:HashTable父类是Dictionary,不是AbstractMap. Map: Map(接口)和Collection都属于集合,但是Map不是Collection的子类 ...

  2. 数据结构(集合)学习之Queue

    集合 框架关系图: Collection接口下面有三个子接口:List.Set.Queue.此篇是关于Queue<E>的简单学习总结. 补充:HashTable父类是Dictionary, ...

  3. 数据结构(集合)学习之Set

    集合 框架关系图: Collection接口下面有三个子接口:List.Set.Queue.此篇是关于Set<E>的简单学习总结. 补充:HashTable父类是Dictionary,不是 ...

  4. 数据结构(集合)学习之Map(二)

    集合 框架关系图 补充:HashTable父类是Dictionary,不是AbstractMap. 一:HashMap中的链循环: 一般来说HashMap中的链循环会发生在多线程操作时(虽然HashM ...

  5. 数据结构(集合)学习之Collection和Iterator

    集合 1.集合与数组 数组(可以存储基本数据类型)是用来存现对象的一种容器,但是数组的长度固定,不适合在对象数量未知的情况下使用. 集合(只能存储对象,对象类型可以不一样)的长度可变,可在多数情况下使 ...

  6. 2019/3/4 java集合学习(二)

    java集合学习(二) 在学完ArrayList 和 LinkedList之后,基本已经掌握了最基本的java常用数据结构,但是为了提高程序的效率,还有很多种特点各异的数据结构等着我们去运用,类如可以 ...

  7. 2019/3/2周末 java集合学习(一)

    Java集合学习(一) ArraysList ArraysList集合就像C++中的vector容器,它可以不考虑其容器的长度,就像一个大染缸一 样,无穷无尽的丢进去也没问题.Java的数据结构和C有 ...

  8. 转:深入Java集合学习系列:HashSet的实现原理

    0.参考文献 深入Java集合学习系列:HashSet的实现原理 1.HashSet概述: HashSet实现Set接口,由哈希表(实际上是一个HashMap实例)支持.它不保证set 的迭代顺序:特 ...

  9. ------------------java collection 集合学习 ----小白学习笔记,,有错,请指出谢谢

    <!doctype html>java对象集合学习记录 figure:first-child { margin-top: -20px; } #write ol, #write ul { p ...

随机推荐

  1. MyBatis基础_连接池与事务、动态SQL、注解开发

    一.MyBatis连接池及事务控制 1.连接池 在实际开发中,都会使用连接池,因为它可以减少获取连接缩消耗的时间.所谓连接池,就是存储数据库连接的容器.连接池中存储一定数量的数据库连接,当线程需要使用 ...

  2. Exchange邮件服务器安全

    Exchange是由微软推出的用于企业环境中部署的邮件服务器.Exchange在逻辑上分为三个层次:网络层(network layer).目录层(directory layer).消息层(messag ...

  3. Elasticsearch系列

    一.Elasticsearch简介 二.elasticsearch集群监控相关

  4. Codeforces 1248C Ivan the Fool and the Probability Theory(推公式)

    题意 一个n*m的网格图,每个格子可以染黑色.白色,问你每个格子最多有一个相邻颜色相同的方案数 n,m<=1e5 思路 我们先处理\(1 \times m\)的情况 设\(f[i][j]\)为前 ...

  5. BZOJ 1614 [Usaco2007 Jan]Telephone Lines架设电话线 (二分+最短路)

    题意: 给一个2e4带正边权的图,可以免费k个边,一条路径的花费为路径上边权最大值,问你1到n的最小花费 思路: 对于一个x,我们如果将大于等于x的边权全部免费,那么至少需要免费的边的数量就是 “设大 ...

  6. Qt中字符串和数值之间的转换

    来自<Qt5.9 C++开发指南> 普通数值和字符串之间的转换 一.从字符串转换为数值 QString类从字符串转换为整数的函数有: int QString::toInt(bool *ok ...

  7. 自定义内建模块 - Python Build Your Own Built-In Module

    在 python 中, 用户可以通过 py 文件创建自定义的 module, 也可以通过 C 创建 dll, 扩展 python module. 当用户在一个正在编辑的模块 module 中, 引入( ...

  8. VFP控制Excel操作集

    ◆访问EXCEL:ExcelSheet = GetObject('','Excel.Sheet')返回结果为类,则成功.例:ExcelSheet = GetObject('','Excel.Sheet ...

  9. JAVA 对守护线程的理解

    1.在start之前,setDaemon. 该现场就成为守护线程了. 2.守护现线程并不是主线程结束,子线程(守护线程)也跟着结束.而是守护线程在没有用户线程运行的情况伴随着JVM退出而结束. 示例代 ...

  10. k8s系列----一个简单的例子

    本实验来自k8s权威指南 解决访问demo出错,关键是靠https://www.cnblogs.com/neutronman/p/8047547.html此链接下面的某个大神的评论 主要yaml文件 ...