2、List接口

List接口

1、List接口的基本介绍

  1. List 接口是 Collection 接口的子接口

    • List集合类中元素有序(既添加顺序和取出顺序一致)、且可重复

      List list = new ArrayList();
      list.add("jack");
      list.add("tom");
      list.add("mary");
      list.add("hap");
      list.add("tom");
      System.out.println(list); //[jack, tom, mary, hap, tom]
      
    • List集合中的每个元素都有其对应的顺序索引,即支持索引

    • List容器中的元素都对应一个整数型的序号记载其在容器中的位置,可以根据序号存取容器中的元素

    • JDK API 中的List接口的实现类有:AbstractList , AbstractSequentialList , ArrayList , AttributeList , CopyOnWriteArrayList , LinkedList , RoleList , RoleUnresolvedList , Stack , Vector

      常用的有:ArrayList 、LinkedList 、Vector

2、List接口的常用方法

  1. void add(int index, Object ele): 在index位置插入ele元素
  2. boolean addAll(int index, Collection eles) :从index位置开始将eles中的所有元素添加进来
  3. Object get(int index) :获取指定index位置的元素
  4. int indexOf(Object obj) : 返回obj在集合中首次出现的位置
  5. int lastIndexOf(Object obj) : 返回obj在当前集合中末次出现的位置
  6. Object remove(int index):移除指定index位置的元素,并返回次元素
  7. Object set(int index, Object ele):设置指定index位置的元素为ele,相当于是替换
  8. List subList(int fromIndex, int toIndex):返回从fromIndex到toIndex位置的子集合 (左闭右开)
List list = new ArrayList();
list.add("张三丰");
list.add("贾宝玉");
list.add(1,"杨过");
System.out.println(list); //[张三丰, 杨过, 贾宝玉]

List list2 = new ArrayList();
list2.add("jack");
list2.add("tom");
list.addAll(1,list2);
System.out.println(list); //[张三丰, jack, tom, 杨过, 贾宝玉]

Object o = list.get(2);
System.out.println(o); //tom

System.out.println(list.indexOf("tom")); //2

list.add("杨过");
System.out.println(list); //[张三丰, jack, tom, 杨过, 贾宝玉, 杨过]
System.out.println(list.lastIndexOf("杨过")); //5

list.remove(0);
System.out.println(list); //[jack, tom, 杨过, 贾宝玉, 杨过]

list.set(1,"玛丽");
System.out.println(list); //[jack, 玛丽, 杨过, 贾宝玉, 杨过]

List returnList = list.subList(0, 2);
System.out.println(returnList); //[jack, 玛丽]

3、List三种遍历方式

package com.hspedu.list_;

import java.util.*;

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

        //List 接口的实现子类 Vector LinkedList
        //List list = new ArrayList();
        List list = new LinkedList();
        //List list = new Vector();
        list.add("jack");
        list.add("tom");
        list.add("鱼香肉丝");
        list.add("北京烤鸭子");

        //遍历
        Iterator iterator = list.iterator();
        while (iterator.hasNext()) {
            Object obj =  iterator.next();
            System.out.println(obj);
        }

        for (Object obj2 : list) {
            System.out.println(obj2);
        }

        for (int i = 0; i < list.size(); i++) {
            System.out.println(list.get(i));
        }

    }
}

4、ArrayList的注意事项

  1. permits all elements, incuding null, ArrayList 可以加入null,并且多个

    ArrayList arrayList = new ArrayList();
    arrayList.add(null);
    arrayList.add("jack");
    arrayList.add(null);
    System.out.println(arrayList); //[null, jack, null]
    
  2. ArrayList是由数组来实现数据存储的

  3. ArrayList基本等同于Vector,除了ArrayList是线程不安全(执行效率高),在多线程情况下,不建议使用ArrayList

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

  1. ArrayList中维护了一个Object类型的数组elementData。 transient Object[] elementData; //transient 表示瞬间,短暂的,表示该属性不会被序列化
  2. 当创建ArrayList对象时,如果使用的是无参构造器,则初始elementData容量为0,第1次添加,则扩容elementData为10,如需要再次扩容,则扩容elementData为1.5倍。
  3. 如果使用的是指定大小的构造器,则初始elementData容量为指定大小,如果需要扩容,则直接扩容elementData为1.5倍。

6、 Vectord底层结构和源码分析

  1. Vector类的定义说明

    public class Vector<E>
    extends AbstractList<E>
    implements List<E>, RandomAccess, Cloneable, java.io.Serializable
    
    
  2. Vector底层也是一个对象数组,protected Object[] elementData;

  3. Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized

    public synchronized E get(int index) {
        if (index >= elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        return elementData(index);
    }
    
  4. 在开发中,需要线程同步安全性,考虑使用Vector

7、Vector和ArrayList的比较

底层结构 版本 线程安全(同步)效率 扩容倍数
ArrayList 可变数组 jdk1.2 不安全,效率高 如果有参构造1.5倍 如果是无参 1.第一次10 2.从第二次开始按1.5扩
Vector 可变数组 jdk1.0 安全,效率不高 如果是无参,默认10,满后,就按2倍扩容 如果指定大小,则每次直接按2倍扩

8、LinkedList底层结构

  • LinkedList的全面说明
    1. LinkedList底层实现了双向链表和双端队列特点
    2. 可以添加任意元素(元素可以重复),包括null
    3. 线程不安全,没有实现同步
  • LinkedList的底层操作机制
    1. LinkedList底层维护了一个双向链表
    2. LinkedList中维护了两个属性first和last分别指向首节点和尾节点
    3. 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点。最终实现双向链表
    4. 所以LinkedList的元素的添加和删除,不是通过数组完成的,相对来说效率较高
public class LinkedList01 {
    public static void main(String[] args) {
        //模拟一个简单的双向链表

        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node hsp = new Node("老汉");

        //连接三个结点,形成双向链表

        jack.next = tom;
        tom.next = hsp;

        hsp.pre = tom;
        tom.pre= jack;

        Node first = jack; //让first引用指向jack,就是双向链表的头结点
        Node last = hsp;   //让last引用指向hsp,就是双向链表的尾结点

        //演示,从头到尾进行遍历
        while (true) {
            if (first == null) {
                break;
            }
            //输出first 信息
            System.out.println(first);
            first = first.next;
        }

        //演示,从尾到头进行遍历
        System.out.println("=======================");
        while (true) {
            if (last == null) {
                break;
            }
            //输出first 信息
            System.out.println(last);
            last = last.pre;
        }

        //演示链表的添加对象/数据,是多么的方便
        //要求,是在 tom ------ 老汉 之间,插入一个对象 smith

        //1. 先创建一个 Node 结点, name 就是 smith
        Node smith = new Node("smith");

        smith.next = hsp;
        smith.pre = tom;
        hsp.pre = smith;
        tom.next = smith;

        //让first 再次指向jack
        first = jack;
        System.out.println("=======================");
        while (true) {
            if (first == null) {
                break;
            }
            //输出first 信息
            System.out.println(first);
            first = first.next;
        }

    }
}

//定义一个Node类,Node对象 表示双向链表的一个结点
class Node {
    public Object item; //真正存放数据
    public Node next; //指向后一个结点
    public Node pre; //指向前一个结点
    public Node(Object name) {
        this.item = name;
    }
    public String toString() {
        return "Node name " + item;
    }
}

/*
	运行结果:
		Node name jack
        Node name tom
        Node name 老汉
        =======================
        Node name 老汉
        Node name tom
        Node name jack
        =======================
        Node name jack
        Node name tom
        Node name smith
        Node name 老汉
*/

9、ArrayList和LinkedList的比较

底层结构 增删的效率 改查的效率
ArrayList 可变数组 较低,数组扩容 较高
LinkedList 双向链表 较高,通过链表追加 较低
  • 如何选择ArrayList和LinkedList:
    1. 如果我们改查的操作多,选择ArrayList
    2. 如果我们增删的操作多,选择LinkedList
    3. 一般来说,在程序中,80% - 90%都是查询,因此大部分情况下会选择ArrayList
    4. 在一个项目中,根据业务灵活选择,也可能这样,一个模块使用的是ArrayList,另外一个模块使用的是LinkedList
posted @ 2022-10-09 20:15  花er公子  阅读(59)  评论(0编辑  收藏  举报