集合框架——List子接口及其实现类,具体用法与源码分析

List子接口

  • 特点:有序,有下标,元素可重复。
  • 方法:
    • add(int index, E element) //将指定的元素插入此列表中的指定位置(可选操作)。
    • indexOf(Object o) //返回此列表中指定元素的第一次出现的索引,如果此列表不包含元素,则返回-1。
    • lastIndexOf([Object o) //返回此列表中指定元素的最后一次出现的索引,如果此列表不包含元素,则返回-1。
    • listIterator() //返回列表中的列表迭代器(按适当的顺序)。
    • addAll(int index, Collection<? extends E> c) //将指定集合中的所有元素插入到此列表中的指定位置(可选操作)。
    • get(int index) //返回此列表中指定位置的元素。
    • subList(int fromIndex, int toIndex) //返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。

四种不同的遍历方法

package com.list.demo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;

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

        List list = new ArrayList();

        list.add("小米");
        list.add("苹果");
        list.add("华为");

        System.out.println(list.indexOf("苹果"));  // 获取元素的索引

        System.out.println("-------------1.for循环遍历-----------------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
        System.out.println("-------------2.for增强循环-----------------");
        for (Object item : list
        ) {
            System.out.println(item);
        }
        System.out.println("-------------3.iterator迭代器-----------------");
        Iterator iterator = list.iterator();
        while (iterator.hasNext()){
            System.out.println(iterator.next());
        }
        System.out.println("-------------4.listIterator迭代器-----------------");
        /*
        *void add(E e)将指定的元素插入列表(可选操作)。
         boolean hasNext() 返回 true如果遍历正向列表,列表迭代器有多个元素。
         boolean hasPrevious()  返回 true如果遍历反向列表,列表迭代器有多个元素。
         E next()        返回列表中的下一个元素,并且前进光标位置。
         int nextIndex()   返回随后调用 next()返回的元素的索引。
         E previous()    返回列表中的上一个元素,并向后移动光标位置。
         int previousIndex() 返回由后续调用 previous()返回的元素的索引。
         void remove() 从列表中删除由 next()或 previous()返回的最后一个元素(可选操作)。
         void set(E e)  用 指定的元素替换由 next()或 previous()返回的最后一个元素(可选操作)。
        *
        * */
        ListIterator listIterator = list.listIterator();
        /*
        * 1.从前往后遍历
        * */
        System.out.println("----------从前往后遍历-----------");
        while (listIterator.hasNext()) {
            System.out.println(listIterator.next());
        }
        /*
         * 2.从后往前遍历
         * */
        System.out.println("----------从后往前遍历-----------");
        while (listIterator.hasPrevious()){
            System.out.println(listIterator.previous());
        }

    }
}

方法解析

  1. subList(int fromIndex, int toIndex) //返回此列表中指定的 fromIndex (含)和 toIndex之间的视图。

    • 该方法会切割了list,其中切割的元素会包含起始位,但不会结束位
  2. add(int index, E element) //将指定的元素插入此列表中的指定位置(可选操作)。

    • 当使用索引时可以在索引位置处插入该元素,其他元素依次后移
  3. remove(int index),如果在加入的数据为int类型时,会自动装箱,当我们用remove方法时不可以直接写数字,直接写数字就会调用索引的重载方法。

package com.list.demo;

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

public class Demo2 {
    public static void main(String[] args) {
        List list = new ArrayList();

//        此时我们加入的数据为数字,会自动装箱-->Integer
        list.add(10);
        list.add(20);
        list.add(30);
        list.add(40);
        list.add(50);

//        list.remove(10);  //IndexOutOfBoundsException
        list.remove(0);  //通过下标索引来删除 10
        list.remove(new Integer(50)); // 通过元素来删除 50
        System.out.println(list);
        list.add(10);
        list.add(20);
        List list1 = list.subList(2, 4);// 40 10
        System.out.println(list1);  //[40, 10]


    }
}

List的实现类

  • ArrayList【重点】

    • 数组结构实现,查询快,增删慢
    • JDK1.2加入,运行效率高(快),线程不安全
  • Vector【了解】:

    • 数组结构实现,查询快,增删慢
    • JDK1.0,运行效率低(慢),线程安全
  • LinkedList:

  • 链表结构实现,增删快,查询慢

  • 链表与数组

    • 链表:

      查看源图像

    • 数组:

查看源图像

ArrayList类【重点】

ArrayList【重点】

  • 数组结构实现,查询快,增删慢
  • JDK1.2加入,运行效率高(快),线程不安全
package com.list.demo;

import com.collection.demo.Student;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.ListIterator;

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

        ArrayList<Object> arrayList = new ArrayList<>();

        Student s1 = new Student("张三", 18, 55);
        Student s2 = new Student("王五", 58, 75);
        Student s3 = new Student("赵六", 19, 45);
        Student s4 = new Student("李四", 28, 65);
//        增加
        arrayList.add(s1);
        arrayList.add(s2);
        arrayList.add(s3);
        arrayList.add(s4);
//      查找
//        1.for
        System.out.println("-------------1.for--------------");
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }
//        2.for增强
        System.out.println("-------------2.for增强--------------");
        for (Object item : arrayList
        ) {
            Student item1 = (Student) item;
            System.out.println(item1);
        }
//        3.迭代器
        System.out.println("-------------3.迭代器--------------");
        Iterator<Object> iterator = arrayList.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
//        4.列表迭代器
        System.out.println("-------------4.列表迭代器--------------");
        ListIterator<Object> listIterator = arrayList.listIterator();
        while (listIterator.hasNext()) {
            System.out.println(listIterator.next());
        }
        System.out.println("-------------4.列表迭代器逆序--------------");
        while (listIterator.hasPrevious()) {
            System.out.println(listIterator.previous());
        }
//        删除
        arrayList.remove(0);  // 通过索引删除
        System.out.println("删除后个数:"+arrayList.size());
        System.out.println(arrayList);
        System.out.println("==============================");
        arrayList.remove(new Student("李四", 28, 65));
        // 并没有删除成功,实际上这里调用了对象的equals()方法,如果想要通过对象的形式删除,要重写equals()方法
        System.out.println("删除后个数:"+arrayList.size());
        System.out.println(arrayList);
        System.out.println("==============================");
//       判断
        System.out.println(arrayList.contains(new Student("赵六", 19, 45)));
        System.out.println(arrayList.isEmpty());
//      查找
        System.out.println(arrayList.indexOf(new Student("赵六", 19, 45)));

    }
}
package com.collection.demo;

import java.util.Objects;

public class Student {
    private String name;
    private int age;
    private int weight;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", weight=" + weight +
                '}';
    }

    // 重写equals
    @Override
    public boolean equals(Object o) {
//     1.如果对象为空
        if (o == null) {
            return false;
        } else {
//            如果是其实例对象,且所有信息都相同,我们就认为其是相同对象
            if (o instanceof Student && this.name.equals(((Student) o).name)
                    && this.age == ((Student) o).age && this.weight == ((Student) o).weight) {
                return true;
            } else {
                return false;
            }
        }

    }


    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setWeight(int weight) {
        this.weight = weight;
    }

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public int getWeight() {
        return weight;
    }

    public Student(String name, int age, int weight) {
        this.name = name;
        this.age = age;
        this.weight = weight;
    }
}

源码分析

private static final int DEFAULT_CAPACITY = 10;  // ArrayList类中定义的容器默认容量
  • 注意:当ArraysList被创建,但还没有添加元素时,此时容量为0
transient Object[] elementData; // non-private to simplify nested class access
// 真实存放对象的数组
private int size;  // 元素个数  默认为0
/**
 * Shared empty array instance used for empty instances.
 */
private static final Object[] EMPTY_ELEMENTDATA = {};

/**
 * 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 = {};
  • 当我们往一个新建的ArrayList中添加元素时,容器的容量会变成默认值,10。
public ArrayList() {
        this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
    }

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}
private void ensureCapacityInternal(int minCapacity) {// 此时minCapacity为1
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //elementData和DEFAULTCAPACITY_EMPTY_ELEMENTDATA此时都是空数组所以成立
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);  
        // DEFAULT_CAPACITY是10 所以现在minCapacity变成了10
    }

    ensureExplicitCapacity(minCapacity);
}

 private void ensureExplicitCapacity(int minCapacity) {
        modCount++;

        // overflow-conscious code
        if (minCapacity - elementData.length > 0)
            // minCapacity=10  ,elementData.length=0 成立
            grow(minCapacity);
    }
 private static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 好几个亿
/**
 * 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) {// minCapacity=10
    // overflow-conscious code
    int oldCapacity = elementData.length; //0
    int newCapacity = oldCapacity + (oldCapacity >> 1);0
    if (newCapacity - minCapacity < 0)//0-10x小于10
        newCapacity = minCapacity;  // newCapacity = 10 新数组的容量变为10
    if (newCapacity - MAX_ARRAY_SIZE > 0) 
        // 不成立,MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8; // 好几个亿
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);
    //newCapacity=10,elementData为空,执行后,elementData变成长度为10的数组
}
public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass()); //返回一个长度为10的数组
}
  • 当初始数组装满时,添加第11个元素,数组会自动扩容
public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!! //此时size + 1=11
    elementData[size++] = e;
    return true;
}
private void ensureCapacityInternal(int minCapacity) {//minCapacity=11
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
        //添加第一个元素后就不再执行
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }
    ensureExplicitCapacity(minCapacity);//minCapacity=11
}
private void ensureExplicitCapacity(int minCapacity) {//minCapacity=11
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)  // 11-10>0
        grow(minCapacity);//minCapacity=11
}
private void grow(int minCapacity) {//minCapacity=11
    // overflow-conscious code
    int oldCapacity = elementData.length; //10
    int newCapacity = oldCapacity + (oldCapacity >> 1);
    //10 + 10/2 = 15 相当于变成原来的1.5倍
    if (newCapacity - minCapacity < 0)//15-11>0
        newCapacity = minCapacity;
    if (newCapacity - MAX_ARRAY_SIZE > 0)//MAX_ARRAY_SIZE=好几个亿,不成立
        newCapacity = hugeCapacity(minCapacity);
    // minCapacity is usually close to size, so this is a win:
    elementData = Arrays.copyOf(elementData, newCapacity);//newCapacity=15
}
public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass()); // 返回扩容后的数组
}
  • 结论:
    1. ArrayList第一次添加元素时,容器的容量会从 0 ------> 10
    2. 当容器装满时,再往里边添加元素时,每次会扩容1.5倍

Vector类【了解】

Vector【了解】:

  • 数组结构实现,查询快,增删慢
  • JDK1.0,运行效率低(慢),线程安全
package com.list.demo;

import java.util.Enumeration;
import java.util.Vector;

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

        Vector<Object> vector = new Vector<>();

        vector.add("香蕉");
        vector.add("菠萝");
        vector.add("哈密瓜");

        // 删除
//        vector.remove("香蕉");
//        vector.clear();
//        vector 枚举器
        Enumeration<Object> elements = vector.elements();
        while (elements.hasMoreElements()) {
            String o = (String) elements.nextElement();
            System.out.println(o);
        }

//        判断
        System.out.println(vector.contains("香蕉"));
        System.out.println(vector.isEmpty());

//        其他方法
        System.out.println(vector.elementAt(0));
        System.out.println(vector.firstElement());
        System.out.println(vector.listIterator());
    }


}
  • 其他方法请查看API文档

LinkedList类【增删常用】

LinkedList:

  • 链表结构实现,增删快,查询慢
  • 双向链表
package com.list.demo;

import com.collection.demo.Student;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.ListIterator;

public class LinkedListTest {
    public static void main(String[] args) {
        LinkedList<Object> list = new LinkedList<>();

        Student s1 = new Student("张三", 18, 55);
        Student s2 = new Student("王五", 58, 75);
        Student s3 = new Student("赵六", 19, 45);
        Student s4 = new Student("李四", 28, 65);

        list.add(s1);
        list.add(s2);
        list.add(s3);
        list.add(s4);

//        删除
        list.remove(s1);
//        list.clear();
//        遍历
//        1.for
        System.out.println("------------1.for----------------");
        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }
//        2.增强for
        System.out.println("------------2.增强for----------------");
        for (Object item : list
        ) {
            System.out.println(item);
        }
//        3.迭代器
        System.out.println("------------3.迭代器----------------");
        Iterator<Object> iterator = list.iterator();
        while (iterator.hasNext()) {
            Student s = (Student) iterator.next();
            System.out.println(s);
        }
//        4.列表迭代器
        System.out.println("------------4.列表迭代器----------------");
        ListIterator<Object> listIterator = list.listIterator();
        while (listIterator.hasNext()) {
            Student s = (Student)listIterator.next();
            System.out.println(s);
        }
        System.out.println("========================");
//       判断
        System.out.println(list.isEmpty());
        list.contains(new Student("张三", 18, 55));
//        其他方法
        System.out.println(list.indexOf(s2));
    }
}

源码分析

  • 链表初始大小
transient int size = 0;
  • 头结点
transient Node<E> first;
  • 尾结点
transient Node<E> last;
  • 构造方法
public LinkedList() {
}
  • add方法
public boolean add(E e) {
    linkLast(e);
    return true;
}
void linkLast(E e) {
    final Node<E> l = last; // null
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode; // last --->newNode
    if (l == null)
        first = newNode;  // first --> newNode,添加第一个元素时
    else
        l.next = newNode;
    size++;  // 链表大小+1
    modCount++;
}

  private static class Node<E> {
        E item;
        Node<E> next;
        Node<E> prev;

        Node(Node<E> prev, E element, Node<E> next) {
            //prev=null,element=添加对象,next=null
            this.item = element;
            this.next = next;
            this.prev = prev;
        }
    }
  • 添加第二个元素时
public boolean add(E e) {
    linkLast(e);
    return true;
}
void linkLast(E e) { // e --> 新增对象
    final Node<E> l = last;  // 上一个节点 l ---> last
    final Node<E> newNode = new Node<>(l, e, null);
    last = newNode; // 新增节点赋值为尾结点last ---> newNode
    if (l == null)
        first = newNode;
    else
        l.next = newNode;// 上一个节点的,下一个节点赋值为新增节点
    size++; // 链表大小加1
    modCount++;
}
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;  // 下一个节点 null
        this.prev = prev; // 上一个节点
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pointer-faker

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值