• 【Java集合】List接口常用方法及实现子类


    List接口

    在这里插入图片描述

    • List集合类中元素有序(即添加和取出顺序一致),且可重复
    • List集合中的每个元素都有其对应的顺序索引,即支持索引;
    • List容器中的元素都对应一个整数型的序号记其在容器中的位置,可以根据序号存取容器中的元素
    • List常用接口有 ArrayList、LinkedList、Vector
    //1.List集合类中元素有序(即添加和取出顺序一致),且可重复
            List list = new ArrayList();
            list.add("Jack");
            list.add("Tom");
            list.add("Marry");
            list.add("Marry");
            System.out.println(list);
            //[Jack, Tom, Marry, Marry]取出输出顺序和存放顺序一致,且可重复
    
            //2.List集合中的每个元素都有其对应的顺序索引,即支持索引
            System.out.println(list.get(2));//Marry
            //3.List容器中的元素都对应一个整数型的序号记其在容器中的位置,可以根据序号存取容器中的元素
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    > 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位置的子集合;

    更多方法可以自行JDK API在线查询下载中文版JavaAPI帮助文档【免费0积分下载】

    //向上转型,用List来接收ArrayList
    List list = new ArrayList();
    
    //1. void add (int index,Object ele) :在index位置插入ele元素;
    list.add("开心的你");
    list.add(0,"帅气的我");//在0位置插入
    System.out.println(list);//[帅气的我, 开心的你]
    
    //2. boolean addAll (int index,Collection eles) :从index位置开始将eles集合中的所有元素添加进来;
    List list1 =  new ArrayList();
    list1.add("Jack");list1.add("Tom");list1.add("Marry");
    list.addAll(1,list1);
    System.out.println(list);//[帅气的我, Jack, Tom, Marry, 开心的你]
    
    //3. Object get (int index) :获取指定index位置的元素;
    System.out.println(list.get(0));//帅气的我
    
    //4. int indexOf (Object obj) :返回obj在集合中首次出现的位置;
    System.out.println(list.indexOf("开心的你"));//4
    
    //5. int lastIndexOf (Object obj) :返回obj在集合中末次出现的位置;
    list.add("Jack");
    System.out.println(list.lastIndexOf("Jack"));//5
    
    //6. Object remove (int index) :移除指定index位置的元素,并返回此元素;
    System.out.println(list.remove(5));//Jack
    System.out.println(list);//[帅气的我, Jack, Tom, Marry, 开心的你]
    
    //7. Object set (int index,Object ele) :设置指定index的位置的元素为ele,相当于是替换;
    list.set(1,"!!!");
    System.out.println(list);//[帅气的我, !!!, Tom, Marry, 开心的你]
    
    //8. List subList  (int fromIndex,int toIndex) :返回从fromIndex到toIndex位置的子集合;
    //返回的子集合: [fromIndex,toIndex) 左闭右开
    System.out.println(list.subList(2,4));//[Tom, Marry]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35

    > List的三种遍历方式

    import java.util.*;
    
    public class ListFor {
        public static void main(String[] args) {
            //List的实现接口子类ArrayList LinkedList Vector
            //List list = new ArrayList();
            //List list = new LinkedList();
            List list = new Vector();
            list.add("熊大");
            list.add("熊二");
            list.add("光头强");
    
            //迭代器iterator遍历
            Iterator iterator = list.iterator();
            while(iterator.hasNext()){
                Object next = iterator.next();
                System.out.println(next);
            }
    
            //增强for遍历
            for (Object o:list) {
                System.out.println(o);
            }
    
            //普通遍历
            for (int i=0;i<list.size();i++){
                System.out.println(list.get(i));
            }
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    > List 排序练习

    import java.util.ArrayList;
    import java.util.List;
    
    public class Demo {
        public static void main(String[] args) {
            //List list = new ArrayList();
            //List list = new LinkedList();
            List list = new Vector();
            list.add(new Book("红楼梦", 36.4f, "曹雪芹"));
            list.add(new Book("水浒传", 19.9f, "施耐庵"));
            list.add(new Book("西游记", 28.8f, "吴承恩"));
    
            //遍历
            for(Object o:list){
                System.out.println(o);
            }
    
            //冒泡排序
            sort(list);
            System.out.println("---- 排序后 ----");
            for(Object o:list){
                System.out.println(o);
            }
        }
        //静态方法:冒泡排序
        //要求价格从小到大
        public static void sort(List list){
    
            for (int i=0;i<list.size();i++){
                for (int j=0;j<list.size()-1-i;j++){
                    //取出对象book
                    Book book1 = (Book) list.get(j);
                    Book book2 = (Book) list.get(j+1);
                    if(book1.getPrice()>book2.getPrice()){
                        //交换
                        list.set(j,book2);
                        list.set(j+1,book1);
                    }
    
                }
            }
        }
    }
    class Book{
        private String name;
        private float price;
        private String author;
    
        @Override
        public String toString() {
            return "书名: "+name+"  价格: "+price+"  作者: "+author;
        }
    
        public Book(String name, float price, String author) {
            this.name = name;
            this.price = price;
            this.author = author;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setPrice(float price) {
            this.price = price;
        }
    
        public void setAuthor(String author) {
            this.author = author;
        }
    
        public String getName() {
            return name;
        }
    
        public float getPrice() {
            return price;
        }
    
        public String getAuthor() {
            return author;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83

    ※ ArrayList 使用注意事项

    • 允许存放任何元素,包括空元素null
    ArrayList list = new ArrayList();
    list.add(null);
    list.add("OK");
    list.add(null);
    System.out.println(list);
    //[null,OK,null]
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • ArrayList 是由数组来实现数据存储的;
    • ArrayList基本等同于 Vector ,除了 ArrayList是线程不安全的,但执行效率高,在多线程的情况下不建议用ArrayList

    ※ ArrayList 底层结构

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

    ※ Vector 底层结构

    • Vector 底层也是一个对象数组,protected Object[ ] elementData;
    • Vector 是线程同步的,即线程安全,Vector类的操作方法带有synchronized
    • 在开发中,需要线程同步安全时,考虑使用Vector

    ※ LinkedList 底层结构 (双向链表和增删改查案例)

    在这里插入图片描述

    • LinkedList 实现了双向链表和双端队列的特点
    • 可以添加任意元素(元素可以重复),包括null;
    • 线程不安全,没有实现同步
    • LinkedList底层维护了一个双向链表;
    • LinkedList中维护了两个属性first和last分别指向 首节点 和 尾节点;
    • 每个节点(Node对象),里面又维护了prev、next、item三个属性,其中通过prev指向前一个,通过next指向后一个节点,最终完成双向链表;
    • 所以 LinkedList的元素的添加和删除不是通过数组完成的,相对来说效率较高;

    双向链表的模拟:

    public class TestLinkedList01 {
        public static void main(String[] args) {
            //模拟一个简单的双向链表
            Node jack = new Node("Jack");
            Node tom = new Node("Tom");
            Node marry = new Node("Marry");
    
            //连接三个节点,形成双向链表
            //jack -> tom -> marry
            jack.next = tom;
            tom.next = marry;
            //jack <- tom <- marry
            marry.pre = tom;
            tom.pre = jack;
    
            Node first = jack;//让first引用指向jack,就是双向链表的首节点
            Node last = marry;//让last引用指向marry,就是双向链表的尾节点
    
            //演示 从头到尾 遍历
            System.out.println("--------- 从头到尾的遍历 --------");
            while(true){
                if(first == null){
                    break;
                }
                //输出first信息
                System.out.println(first);
                first = first.next;//输出完以后,first指向下一个
                /*
                        Node name = Jack
                        Node name = Tom
                        Node name = Marry
                        进程已结束,退出代码0
                 */
            }
            //从尾到头的遍历
            System.out.println("--------- 从尾到头遍历 --------");
            while(true){
                if(last == null){
                    break;
                }
                //输出last信息
                System.out.println(last);
                last = last.pre;//输出完以后,first指向下一个
                /*
                        Node name = Marry
                        Node name = Tom
                        Node name = Jack
                 */
            }
    
            //演示链表的添加对象/数据
            //在tom和marry之间插入一个对象
            //1.先创建一个Node节点,name为smith
            Node smith = new Node("Smith");
            //2.把smith加入双向链表
            smith.next = marry;
            smith.pre = tom;
            marry.pre = smith;
            tom.next = smith;
            //3.让first再次指向jack
            first =  jack;
            //演示 从头到尾 遍历
            System.out.println("--------- 插入smith后 从头到尾的遍历 --------");
            while(true){
                if(first == null){
                    break;
                }
                //输出first信息
                System.out.println(first);
                first = first.next;//输出完以后,first指向下一个
            }/*
                    Node name = Jack
                    Node name = Tom
                    Node name = Smith
                    Node name = Marry
            */
    
    
        }
    
    
    }
    
    
    //定义一个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;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96

    LinkedList的增删改查案例:

    import java.util.Iterator;
    import java.util.LinkedList;
    
    public class LinkListCRUD {
        public static void main(String[] args) {
            LinkedList linkedList = new LinkedList();
    
            //增
            linkedList.add(1);//size=0添加一个新节点,首尾指针都指向这个新节点
            linkedList.add(2);//last指向新节点,first还是指向第一个节点,next指向新节点
            linkedList.add(3);
            System.out.println("增后: "+linkedList);
    
            //删
            linkedList.remove();//默认删除第一个
            System.out.println("删后: "+linkedList);//就是去掉指针
    
            //改
            linkedList.set(1,999);
            System.out.println("改后: "+linkedList);
    
    
            //查
            //get(1) 得到双向链表的第二个对象
            Object o = linkedList.get(1);
            System.out.println(o);//999
    
            //因为LinkedList是实现了List接口,所以遍历方式:
            Iterator iterator = linkedList.iterator();
            while (iterator.hasNext()) { //快捷输入itit
                Object next =  iterator.next();
                System.out.println(next);
            }
            //还有增强for 和普通for 遍历
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    (可以自行debug看一下调用方法的实现)


    > ArrayList 和 LinkedList 比较

    集合底层结构增删的效率改查的效率
    ArrayList可变数组较低,数组扩容较高
    LinkedList双向链表较高,通过链表追加较低

    如何选择 ArrayList 和 LinkedList :

    1. 如果改查的操作较多,选择 ArrayList;
    2. 如果增删的操作较多,选择 LinkedList;
    3. 一般程序中,80%-90%都是查询,因此大部分会使用ArrayList;
    4. 在项目中,灵活选择,可以一个模块用LinkedList,一个模块用ArrayList;

    多线程的情况还是考虑 Vector ,因为它是线程安全的

  • 相关阅读:
    OJ第三篇
    基于Spark的网上商城用户行为分析
    vuex常用属性
    【信号处理】基于EEG脑电信号的自闭症预测典型方法实现
    袋鼠云产品功能更新报告01期丨用诚心倾听您的需求
    阿里二面:有一个 List 对象集合,如何优雅地返回给前端?
    C语言笔记-17-Linux基础-用户与权限
    求过去半年内连续30天以上每天都有1000元以上成交的商铺
    【springcloud】一些项目结构模式
    Proxy 代理对象使用详解即原理总结
  • 原文地址:https://blog.csdn.net/Lov1_BYS/article/details/128123735