Java基础篇-集合(List)

157 阅读3分钟

前言

Java有多种方式保存对象引用,如数组,但是数组具有固定尺寸,故提供了一些集合类(也称容器类)来解决这个问题。本文将详细的介绍List集合。

Java List集合简介

List是一种存储类的容器,它有一些特性:

  • 集合中的元素是有序的
  • 集合中的元素是可以重复
  • 插入时可以选择具体的位置
  • 可以通过索引来访问/操作元素

Java集合主要由2大体系构成,分别是Collection体系和Map体系,其中Collection和Map分别是2大体系中的顶层接口。

Collection主要有三个子接口,分别为List(列表)、Set(集)、Queue(队列)。其中,List、Queue中的元素有序可重复,而Set中的元素无序不可重复。

在List集合中,我们常用到是ArrayListLinkedList这两个List的实现类

ArrayList

ArrayList底层基于数组实现
特点:

  • 容量不固定,随元素增多而扩容, 扩容为时,先取旧容量的1.5倍,然后和新增数据之后的长度比较取大的
  • 非线程安全的集合类

ArrayList扩容相关源码:

private void grow(int minCapacity) {  
    // overflow-conscious code  
    int oldCapacity = elementData.length;  
    // 取原有数组长度增加3/2,>>即二进制右移1位,相当于原数字大小除以2
    int newCapacity = oldCapacity + (oldCapacity >> 1); 
    // newCapacity(旧容量的1.5倍)和minCapacity(新增数据之后的长度),谁大取谁
    if (newCapacity - minCapacity < 0)  
    newCapacity = minCapacity;  
    // 如果取得的最大的数比MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8(MAX_VALUE = 2147483647) 还大,(通常不会有这种情况
    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 那样进行扩容,新增元素只需加上前后节点引用
  • 实现Deque接口,具有双端队列的特性,既可以先进先出,也可以先进后出,所以也可以作为栈来使用
  • 非线程安全的集合类

LinkedList中的单个元素node 相关源码:

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;  
    }  
}

ArrayList 和 LinkedList 比较(面试常问)

  1. 底层数据结构不同:ArrayList底层基于数组,LinkedList底层基于链表
  2. 效率不同:
  • ArrayList底层基于数组,所以在随机访问元素(get、set)的时候效率高,直接通过下标取值,塞值。
  • 插入和删除的时候(remove、add):如果删除或新增在末尾的话差不多;如果新增或删除在中间数据的话,LinkedList效率高,因为底层基于链表,所以只需要更改指针即可,而ArrayList需要通过移动数组来实现。
  1. 开销不同: LinkedList需要存储节点信息、前后节点指针信息。ArrayList当原数组满了的时候,会按原数组长度的3/2倍进行扩容,会存在一些预留空间。

示例比较

  
import java.util.ArrayList;  
import java.util.LinkedList;  
import java.util.List;  
  
public class JavaListTest {  
        public static void main(String[] args) throws InterruptedException {  
        ArrayList<Integer> arrayList = new ArrayList<>();  
        LinkedList<Integer> linkedList = new LinkedList<>();  
        for (int i = 0; i < 10000; i++) {  
            arrayList.add(i);  
            linkedList.add(i);  
        }  
        System.out.println("ArrayList add Time = " + addData(arrayList));  
        System.out.println("LinkedList add Time = " + addData(linkedList));  
        System.out.println("ArrayList search Time = " + searchData(arrayList));  
        System.out.println("LinkedList search Time = " + searchData(linkedList));  
    }  
  
    public static Long addData(List list) {  
        Long start = System.currentTimeMillis();  
        for (int i = 10000; i < 20000; i++) {  
            list.add(i, i);  
        }  
        return System.currentTimeMillis() - start;  
    }  


    public static Long searchData(List list) {  
        Long start = System.currentTimeMillis();  
        for (int i = 0; i < 20000; i++) {  
            list.get(i);  
        }  
            return System.currentTimeMillis() - start;  
    }  
  
}

运行结果:

ArrayList add Time = 5
LinkedList add Time = 4
ArrayList search Time = 2
LinkedList search Time = 237