JAVA------集合之List

一、List接口

1、List集合类中元素有序,且可重复

2、List 集合中的每个元素都有其对应的顺序索引,即支持索引

package com.level7.List_;

import java.util.ArrayList;
import java.util.List;

public class List_ {
    public static void main(String[] args) {
        // 1.List集合类中元素有序,且可重复
        List list = new ArrayList();
        list.add(123);
        list.add("xrj");
        list.add("xyy");
        list.add("xrj");
        System.out.println(list);

        // 2.List 集合中的每个元素都有其对应的顺序索引,即支持索引
        System.out.println(list.get(2));
    }
}

List接口常用方法

package com.level7.List_;

import java.util.ArrayList;
import java.util.List;

public class ListMethod {
    public static void main(String[] args) {
        List list = new ArrayList();
        list.add("张三丰");
        list.add("贾宝玉");

        // void add(int index, Object ele):在 index 位置插入 ele 元素
        list.add(1, "xrj");
        System.out.println(list);

        // boolean addAll(int index, Collection eles):从 index 位置开始将 eles 中的所有元素添加进来
        List list2 = new ArrayList();
        list2.add("jack");
        list2.add("tom");
        list.addAll(2, list2);
        System.out.println(list);

        // Object get(int index):获取指定 index 位置的元素
        System.out.println(list.get(3));

        // int indexOf(Object obj):返回 obj 在集合中首次出现的位置
        System.out.println(list.indexOf("tom"));

        // int lastIndexOf(Object obj):返回 obj 在当前集合中末次出现的位置
        list.add("xrj");
        System.out.println(list);
        System.out.println(list.lastIndexOf("xrj"));

        // Object remove(int index):移除指定 index 位置的元素,并返回此元素
        System.out.println(list.remove(0));
        System.out.println(list);

        // Object set(int index, Object ele):设置指定 index 位置的元素为 ele , 相当于是替换.
        list.set(1, "玛丽");
        System.out.println(list);

        // List subList(int fromIndex, int toIndex):返回从 fromIndex 到 toIndex 位置的子集合
        // fromIndex <= subList < toIndex
        List returnlist = list.subList(1, 4);
        System.out.println(returnlist);
    }
}


二、ArrayList底层结构和源码分析

ArrayList注意事项

1、ArrayList可以加入null,并且可以放多个

2、ArrayList是由数组来实现数据存储的

3、ArrayList基本等同于VectorArrayList是线程不安全的,因为源码没有synchronized关键字修饰,但是执行效率高。多线程情况下不建议使用ArrayList


ArrayList源码分析

1、ArrayList中维护了一个Object类型的数组transient Object[] elementData; transient表示瞬间、短暂,表示该属性不会被序列化

2、当创建ArrayList对象时,如果使用的是无参构造器,则初始化elementData的容量为0,第一次添加,则扩容elementData为10,如需再次扩容,则扩容

elementData为1.5倍

3、如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如需扩容,直接扩容为elementData的1.5倍

package com.level7.List_;

import java.util.ArrayList;

public class ArrayListSource {
    public static void main(String[] args) {

        ArrayList list = new ArrayList();
        // ArrayList list = new ArrayList(8);
        // 使用 for 给 list 集合添加 1-10 数据
        for (int i = 1; i <= 10; i++) {
            list.add(i);
        }
        // 使用 for 给 list 集合添加 11-15 数据
        for (int i = 11; i <= 15; i++) {
            list.add(i);
        }
        list.add(100);
        list.add(200);
        list.add(null);
    }
}

使用无参构造器创建ArrayList

1、执行ArrayList list = new ArrayList();elementData赋一个空数组

2、执行list.add(i); 由于是无参构造,所以第一次扩容容量为10

​ 2.1 add时,先判断当前容量是否可用(初始容量为0)。先确定是否需要扩容,然后在赋值

在这里插入图片描述

​ 2.2 计算当前所需最小容量

在这里插入图片描述

​ 2.3 传入的Object[] elementData就是elementDataminCapacity是1,elementData初始的时候就是空,因此执行if中的语句,DEFAULT_CAPACITY

​ 是10,因此返回10

​ 2.4 现在所需最小容量为10,但是elementData的容量为0,所以需要扩容,进入grow方法进行扩容。modCount++记录集合被修改的次数,即add的次数

​ 2.5 oldCapacity现在是0,newCapacityoldCapacity的1.5倍,第一次扩容,所以newCapacity也是0,然后0-10小于0,执行第一个if,将newCapacity置为10,最后执行elementData = Arrays.copyOf(elementData, newCapacity); 使用copyOf将原数组拷贝到新数组,并将新数组扩容。

​ 2.6 然后就一直返回,将当前add的值加入list中

在这里插入图片描述

3、当前容量为10,如果需要存放11个数据时,会继续扩容,这时就是扩容到原来的1.5倍即15个大小



使用有参构造器创建ArrayList

1、执行ArrayList list = new ArrayList(8); 为list创建一个大小为8的数组,后边容量不够就扩容为原始容量1.5倍,和上边流程一致



三、Vector

Vector介绍

1、Vector底层也是一个数组 protected Object[] elementData;

2、Vector是线程同步的,即线程安全,它的方法都带有synchronized关键字

3、Vector的无参构造默认初始化数组大小为10,如果需要扩容,每次扩容两倍

4、Vector的有参构造,初始化时容量为指定大小,需要扩容,每次扩容两倍



Vector底层分析

package com.level7.List_;

import java.util.Vector;

public class Vector_ {
    public static void main(String[] args) {
        // Vector vector = new Vector();
        Vector vector = new Vector(8);
        for (int i = 0; i < 20; i++) {
            vector.add(i);
        }
        vector.add(100);
        System.out.println("vector=" + vector);
    }
}

Vector无参构造

1、执行Vector vector = new Vector();语句进入无参构造方法,调用有参构造方法,初始容量为10

​ 初始指定initialCapacity为10,capacityIncrement为0

2、执行vector.add(i),先判断是否需要扩容,然后赋值,modCount表示add多少次

在这里插入图片描述

3、如果当前所需最小容量大于数组容量,那么就扩容

4、如果需要扩容,就进入grow方法。oldCapacity是原数组大小,如果capacityIncrement大于0,那么我们的容量就增加capacityIncrement,但是capacityIncrementment默认为0,所以newCapacity就是oldCapacity的两倍,然后使用copyOf方法扩容

5、依次返回,将add的值加进去


Vector有参构造

1、执行Vector vector = new Vector(8);,进入该方法,数组大小初始化为指定大小,如果需要继续扩容和无参构造一样

ArrayList和Vector对比

底层结构出现版本线程安全扩容倍数
ArrayListtransient Object[] elementDataJDK1.2不安全,效率高如果是有参构造,每次扩容1.5倍。如果是无参,初始化大小为0,第一次扩容为10,然后每次扩容1.5倍。
Vectorprotected Object[] elementDataJDK1.0安全,效率不高如果是无参,初始化大小为10,每次扩容2倍。如果指定大小,每次扩容2倍。



四、LinkedList

LinkedList介绍

1、LinkedList底层实现了双向链表和双端队列特点

2、可以添加任意元素(元素可以重复),包括null

3、线程不安全,没有实现同步

1、LinkedList底层维护了一个双向链表

2、LinkedList中维护了两个属性firstlast分别指向首节点和尾结点

3、每个节点(Node对象),里边又维护了prevnextitem三个属性,其中通过prev指向前一个,通过next指向后一个节点


模拟双向链表

package com.level7.List_;

public class LinkedList01 {
    public static void main(String[] args) {
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node xrj = new Node("xrj");
        jack.next = tom;
        tom.next = xrj;
        tom.pre = jack;
        xrj.pre = tom;

        Node first = jack;
        Node last = xrj;

        // 在tom和xrj之间增加一个xyy
        Node xyy = new Node("xyy");
        xyy.pre = xrj.pre;
        xyy.next = tom.next;
        tom.next = xyy;
        xrj.pre = xyy;

        while (first != null) {
            System.out.println(first);
            first = first.next;
        }

        while (last != null) {
            System.out.println(last);
            last = last.pre;
        }
    }
}

class Node {
    public Object item;
    public Node next;
    public Node pre;

    public Node(Object item) {
        this.item = item;
    }

    @Override
    public String toString() {
        return "item = " + item;

    }
}

LinkedList底层操作机制

package com.level7.List_;

import java.util.LinkedList;

public class LinkedListSource {
    public static void main(String[] args) {
        LinkedList list = new LinkedList();
        list.add(10);
        list.add(15);
        list.add(20);
        list.add(1, 50);
        System.out.println(list);

        // 删除节点
        list.remove();  // 默认删除第一个节点
        System.out.println(list);

        // 修改某个节点
        Object origin = list.set(1, 100);  // 返回的是修改前的元素
        System.out.println(origin);
        System.out.println(list);

        // 得到节点对象
        Object o = list.get(2);
        System.out.println(o);
    }
}

插入元素

1、LinkedList list = new LinkedList();调用该语句后,执行构造器

在这里插入图片描述

2、list.add(10);调用add方法后。会进入linkLast(e)这个方法

在这里插入图片描述

3、在该方法中,首先让 l 指向当前链表的尾指针即last节点,然后构建新节点,他的pre指针就是 l ,next指针为空,item就是当前add的值。然后让last指针指向新的节点,如果 l 为空,表示当前链表为空,那么这个新节点就是链表第一个节点,就让first指针也指向这个节点。如果不是第一次add,则 l 指向上一个节点,一定不为空,然后 l.next = newNode;让上一个节点的next指针指向这个新节点

在这里插入图片描述

4、这是new Node<>(l, e, null)构造器



指定位置插入元素

1、list.add(1, 50);在第一个位置插入50这个元素,进入public void add(int index, E element)这个方法,首先判断当前插入的位置index是否合法,即index >= 0 && index <= size;如果不合法会抛出下标越界异常。然后判断如果index == size说明在末尾插入,否则执行else的语句

在这里插入图片描述

2、进入node方法,首先找到插入的位置x是一个Node类型

3、进入linkBefore方法,succ就是需要插入的位置,然后将元素插入进去

在这里插入图片描述



删除节点

1、执行list.remove();默认删除第一个节点。执行该语句后进入remove方法

2、判断first节点是否为空,如果为空就抛出异常

3、进入private E unlinkFirst(Node<E> f),f为first节点,next为它的下一个节点,将要删除的这个f的item和next置为空,然后让first节点指向它的下一个节点,首节点就被删除了。如果next节点也为空,说明链表为空,那么让last也为空,否则就是让当前头结点的pre指针为空,然后返回删除的元素。

在这里插入图片描述

ArrayList和LinkedList的比较

底层结构增删的效率改查效率
ArrayList可变数组较低,数组扩容较高
LinkedList双向链表较高,通过链表追加较低
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值