java集合之List

写在前面

集合类是java语言对数据结构的实现

在这里插入图片描述


List接口介绍

java.util.List是有序的 collection(也称为序列),继承自Collection接口,是单列集合的一个重要分支。此接口的用户可以对列表中每个元素的插入位置进行精确地控制。用户可以根据元素的整数索引(在列表中的位置)访问元素,并搜索列表中的元素。
特点

  1. 元素有序,即存入的顺序和取出的顺序一致。
  2. 通过索引可以精确操作集合中的元素。
  3. 允许重复

List接口中常用方法

List作为Collection集合的子接口,不但继承了Collection接口中的全部方法,而且还增加了一些根据元素索引来操作集合的特有方法,如下:

public void add(int index, E element): 将指定的元素,添加到该集合中的指定位置上。
public E get(int index):返回集合中指定位置的元素。
public E remove(int index): 移除列表中指定位置的元素, 返回的是被移除的元素。
public E set(int index, E element):用指定元素替换集合中指定位置的元素,返回值的更新前的元素。

List的子类

List的子类常用的由三个

  • ArrayList
  • LinkedList
  • Vector
1 . ArrayList

java.util.ArrayList是List 接口的大小可变数组的实现,换言之它是数组结构的集合类。

因此它具有数组的特点,即 查询快,增删慢

//ArrayList的底层就是一个Object[]数组。
transient Object[] elementData;

它实现了所有可选列表操作,并允许包括 null 在内的所有元素。除了实现 List 接口外,此类还提供一些方法来操作内部用来存储列表的数组的大小。
(ArrayList类大致上等同于 Vector 类,除了它是不同步的(多线程)。)

由于日常开发中使用最多的功能为查询数据、遍历数据,所以ArrayList是最常用的集合。

许多程序员开发时非常随意地使用ArrayList完成任何需求,这很不严谨,也很不专业。

2. LinkedList

java.util.LinkedList是List 接口的链接列表实现,换言之它是链表结构的集合类。因此它具有链表的特点,即查询慢,增删快

java.util.LinkedList不同步的(多线程)。

java.util.LinkedList是一个双向链表,结构如下:
在这里插入图片描述

LinkedList

实际开发中对一个集合元素的添加与删除经常涉及到首尾操作,而LinkedList提供了大量首尾操作的方法。

public void addFirst(E e):将指定元素插入此列表的开头。
public void addLast(E e):将指定元素添加到此列表的结尾。
public E getFirst():返回此列表的第一个元素。
public E getLast():返回此列表的最后一个元素。
public E removeFirst():移除并返回此列表的第一个元素。
public E removeLast():移除并返回此列表的最后一个元素。
public E pop():从此列表所表示的堆栈处弹出一个元素。
public void push(E e):将元素推入此列表所表示的堆栈。此方法等效于addFirst(E e)
public boolean isEmpty():如果列表不包含元素,则返回true。此方法等效于addLast(E e)
3. Vector

和ArrayList相似,唯一的区别是,Vector类是同步的(单线程)。


面试题

ArrayList与LinkedList的区别?

  • ArrayList的底层是基于数组实现的,LinkedList的基于双向链表实现的。它们都是线程不安全的。
  • LinkedList比ArrayList更占内存,因为LinkedList的节点除了存储数据,还存储了两个指针域,分别指向前一个元素和后一个元素。
  • ArrayList查询快,增删慢。
  • LinkedList查询慢,增删快。
补充
  1. ArrayList
  • public E get(int index) : 获取指定索引位置的元素,时间复杂度 O(1)
  • public boolean add(E e):先将原数组数据复制到容量+1的数组中,然后在尾部追加e,时间复杂度 O(1)
  • public E remove(int index):底层需要复制数组,时间复杂度 O(n)
  • public void add(int index, E element):底层需要复制数组,时间复杂度 O(n)
	//移除指定索引处的元素
	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; 

        return oldValue;
    }

ArrayList的add()方法,如果只是添加到尾部,效率也是非常高的。但是如果要是向指定索引位置添加,那么效率就会下降,因为它会调用System.arraycopy()方法。

源码如下:

    //向尾部添加元素
    public boolean add(E e) {
        ensureCapacityInternal(size + 1);  
        elementData[size++] = e;
        return true;
    }
    //向指定位置添加元素
    public void add(int index, E element) {
        rangeCheckForAdd(index);

        ensureCapacityInternal(size + 1);  
        //调用数组的复制方法
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
  1. LinkedList
  • public E getFirst()/getLast:获取头尾,时间复杂度 O(1)
  • public void addFirst(E e)/addLast(E e):添加到头尾,时间复杂度 O(1)
  • public boolean add(E e):底层源码和addLast(E e)相同,时间复杂度 O(1)
  • public E removeFirst()/removeLast():时间复杂度 O(1)
  • public E remove():实际调用的是removeFirst(),删除第一个元素,时间复杂度 O(1)
  • public E get(int index):获取指定索引位置的元素,底层采用二分查找,虽然效率有所提升,但是还是很慢,时间复杂度 O(n/2)
  • public boolean remove(Object o):删除指定元素,需要遍历链表,时间复杂度 O(n)
  • public E remove(int index):删除指定索引位置的元素,底层采用二分查找,时间复杂度 O(n/2)

数组Array和集合的区别?

  • 数组是静态的,容量固定。无法动态扩容

补充:

  1. 有些博客里说:数组声明了它容纳的元素的类型,而集合不声明,这句话是错误的。
    集合如果不声明容纳的元素类型,就等同于它申明了Object类型。

  2. 数组的存放的类型只能是一种(基本类型/引用类型),集合存放的类型可以不是一种,这句话也是错误的。如果new一个Object数组,那么它既能存放基本类型,也能存放引用类型。

public class Demo02 {
    public static void main(String[] args) {
        Object[] o = new Object[10];
        
        o[1] = new Layman("layman", 18);
        o[2] = "ABC";
        o[3] = 1;
        o[3] = new Object[3];
        o[4] = 12.22;
        o[5] = LocalDateTime.now();
    }
}
@Data
@AllArgsConstructor
class Layman{
    private String name;
    private Integer age;
}

因为数组不能动态扩容(早期通过链表实现,非常复杂),所以引入集合类。

集合类是java语言对数据结构的实现

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值