Java中 List集合接口及其主要的实现类ArrayList,Vector,LinkedList的详解

简介: Java中 List集合接口及其主要的实现类ArrayList,Vector,LinkedList的详解

一、ArrayList:作为list接口的主要实现类;线程不安全,效率高;底层使用Object[] elementData存储

1、List接口基本介绍

2、list接口中的常用方法

@Test
    public void test1(){
    //1.List集合类中元素有序(即添加顺序和取出顺序一致)、且可重复
        List list = new ArrayList();
        list.add("jack");
        list.add("tom");
        list.add("mary");
        list.add("tom");
        System.out.println("list=" + list);
        //2.List集合中的每个元素都有其对应的顺序索引,即支持索引
        //索引是从0开始的
        System.out.println(list.get(3));//tom
        ArrayList list=new ArrayList();
        list.add(45);
        list.add("aa");
        list.add("你好");
        list.add("456");
        System.out.println(list);
        //1.void add(int index,Object ele):在index位置插入ele元素
        list.add(1,"bb");
        System.out.println(list);
        //2.boolean addAll(int index,Collection eles):从index位置开始将eles中的所有元素添加进来
        List list1 = Arrays.asList(1, 2, 3);
        list.addAll(list1);
        System.out.println(list);
        System.out.println(list.size());
        //3.Object get(int index):获取指定index位置元素的值
        Object dd = list.get(1);
        System.out.println(dd);
        //4.int indexOf(Object obj),返回obj在当前集合中首次出现的位置
        int obj = list.indexOf("aa");
        System.out.println(obj);
        //5.int LastIndexOf(Object obj),返回obj在当前集合中末次出现的位置
        int lastIndexOf = list.lastIndexOf(45);
        System.out.println(lastIndexOf);
        //6.Object remove(int index),移除指定index位置的元素,并返回此元素
        list.remove(2);
        System.out.println(list);
        //7.Object set(int index,Object ele),设置指定index位置的元素为ele
        list.set(0,78);
        System.out.println(list);
        //8.List subList(int fromIndex,int toIndex):返回从fromIndex到toIndex位置的(左闭右开)子集合
        System.out.println(list.subList(3,5));
    }

输出结果为:

[45, aa, 你好, 456]

[45, bb, aa, 你好, 456]

[45, bb, aa, 你好, 456, 1, 2, 3]

8

bb

2

0

[45, bb, 你好, 456, 1, 2, 3]

[78, bb, 你好, 456, 1, 2, 3]

[456, 1]

List接口的相关练习

代码实现如下

public class ListExercise02 {
    @SuppressWarnings({"ALL"})
    public static void main(String[] args) {
//        List list = new ArrayList();
//        List list = new LinkedList();
        List list = new Vector();
        Book book = new Book("红楼梦", 10.5, "曹雪芹");
        Book book1 = new Book("西游记", 7.4, "吴承恩");
        Book book2 = new Book("水浒传", 9.1, "施耐庵");
        list.add(book);
        list.add(book1);
        list.add(book2);
        for (Object obj : list) {
            System.out.println(obj);
        }
        sort(list);
        System.out.println("排序后");
        for (Object obj : list) {
            System.out.println(obj);
        }
    }
    //冒泡排序,价格从小到大
    public static void sort(List list) {
        int listSize = list.size();
        for (int i = 0; i < listSize - 1; i++) {
            for (int j = 0; j < listSize - 1 - i; j++) {
                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 double price;
    private String author;
    public Book(String name, double price, String author) {
        this.name = name;
        this.price = price;
        this.author = author;
    }
    @Override
    public String toString() {
        return "名称:" + name + "\t价格:" + price + "\t作者:" + author;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
}

输出结果如下:

名称:红楼梦  价格:10.5 作者:曹雪芹
名称:西游记  价格:7.4  作者:吴承恩
名称:水浒传  价格:9.1  作者:施耐庵
排序后
名称:西游记  价格:7.4  作者:吴承恩
名称:水浒传  价格:9.1  作者:施耐庵
名称:红楼梦  价格:10.5 作者:曹雪芹

以上就是常用的list集合中的方法,仅供参考学习!

下面是关于ArrayList的注意事项如下

代码如下

@SuppressWarnings({"all"})
public class ArrayListDetail {
    public static void main(String[] args) {
        //可以放所有元素,包括null元素
        //ArrayList 是线程不安全的,可以看源码 没有synchronized
        /*
         public boolean add(E e) {
                ensureCapacityInternal(size + 1);  // Increments modCount!!
                elementData[size++] = e;
                return true;
            }
         */
        ArrayList arrayList = new ArrayList();
        arrayList.add(null);
        arrayList.add("jack");
        arrayList.add(null);
        System.out.println(arrayList);
    }
}

输出结果如下:

[null, jack, null]

ArrayList的底层源码分析,先看结论

Vector的底层源码分析

分析Vector源码代码如下:

public class Vector_ {
    public static void main(String[] args) {
        Vector vector = new Vector(8);
        for (int i = 0; i < 10; i++) {
            vector.add(i);
        }
        vector.add(100);
        System.out.println("vector=" + vector);
        //解读源码:
        //1.new Vector() 底层
        /*
             public Vector() {
                    this(10);
                }
        补充:如果是Vector vector = new Vector(8);
        走的方法:
         public Vector(int initialCapacity) {
                this(initialCapacity, 0);
            }
        2.vector.add(i);
        2.1 //下面这个方法就添加数据到vector集合
                public synchronized boolean add(E e) {
                modCount++;
                ensureCapacityHelper(elementCount + 1);
                elementData[elementCount++] = e;
                return true;
            }
        2.2 确定是否需要扩容 条件:minCapacity - elementData.length > 0
         private void ensureCapacityHelper(int minCapacity) {
                // overflow-conscious code
                if (minCapacity - elementData.length > 0)
                    grow(minCapacity);
            }
        2.3 //如果需要的数组大小不够用,就扩容,扩容的算法
             private void grow(int minCapacity) {
                // overflow-conscious code
                int oldCapacity = elementData.length;
                int newCapacity = oldCapacity + ((capacityIncrement > 0) ?
                                                 capacityIncrement : oldCapacity);
                //就是扩容两倍
                if (newCapacity - minCapacity < 0)
                    newCapacity = minCapacity;
                if (newCapacity - MAX_ARRAY_SIZE > 0)
                    newCapacity = hugeCapacity(minCapacity);
                elementData = Arrays.copyOf(elementData, newCapacity);
            }
         */
    }
}

Vector和ArrayList的比较如下:

LinkedList的全面说明

LinkedList底层结构如下

演示双向链表,代码如下

public class LinkedList0 {
    public static void main(String[] args) {
        //模拟一个简单的双向链表
        Node jack = new Node("jack");
        Node tom = new Node("tom");
        Node ly = new Node("ly");
        //连接三个结点,形成双向链表
        //jack->tom->ly
        jack.next = tom;
        tom.next = ly;
        //ly->tom->jack
        ly.pre = tom;
        tom.pre = jack;
        Node first = jack;//让first引用指向jack,就是双向链表的头结点
        Node last = ly;//让last引用指向ly,就是双向链表的尾结点
        //演示从头到尾进行遍历
        System.out.println("===演示从头到尾进行遍历===");
        while (true) {
            if (first == null) {
                break;
            }
            //输出first信息
            System.out.println(first);
            first = first.next;
        }
        //演示,从尾到头进行遍历
        System.out.println("===从尾到头进行遍历===");
        while (true) {
            if (last == null) {
                break;
            }
            System.out.println(last);
            last = last.pre;
        }
        //演示链表添加对象/数据
        //要求:在tom与ly之间,插入一个对象,smith
        //1.先创建一个Node结点,name就是smith
        Node smith = new Node("smith");
        //下面就把smith加入到双向链表了
        smith.next = ly;
        smith.pre = tom;
        tom.next = smith;
        ly.pre = smith;
        first = jack;
        System.out.println("===演示从头到尾进行遍历===");
        while (true) {
            if (first == null) {
                break;
            }
            System.out.println(first);
            first = first.next;
        }
        System.out.println("===从尾到头进行遍历===");
        last = ly;
        while (true) {
            if (last == null) {
                break;
            }
            System.out.println(last);
            last = last.pre;
        }
    }
}
//定义一个Node类,Node对象表示双向链表的一个结点
class Node {
    public Object item;//真正存放数据
    public Node next; //指向下一个结点
    public Node pre;//指向前一个结点
    public Node(Object name) {
        this.item = name;
    }
    @Override
    public String toString() {
        return "Node name=" + item;
    }
}

输出结果如下

===演示从头到尾进行遍历===
Node name=jack
Node name=tom
Node name=ly
===从尾到头进行遍历===
Node name=ly
Node name=tom
Node name=jack
===演示从头到尾进行遍历===
Node name=jack
Node name=tom
Node name=smith
Node name=ly
===从尾到头进行遍历===
Node name=ly
Node name=smith
Node name=tom
Node name=jack

LinkedList底层源码分析,代码如下

public class LinkedListCRUD {
    public static void main(String[] args) {
        LinkedList linkedList = new LinkedList();
        linkedList.add(1);
        linkedList.add(2);
        linkedList.add(3);
        System.out.println("linkedList=" + linkedList);
        //演示一个删除
        linkedList.remove();//这里默认删除是第一个结点
        System.out.println("linkedList=" + linkedList);
        //修改某个结点对象
        linkedList.set(1, 99);
        System.out.println("linkedList=" + linkedList);
        //得到某个结点对象
        Object o = linkedList.get(1);
        System.out.println(o);//99
        //因为LinkedList是实现了List接口,遍历方式
        System.out.println("===LinkedList遍历使用迭代器===");
        Iterator iterator = linkedList.iterator();
        while (iterator.hasNext()) {
            Object linkedList1 = iterator.next();
            System.out.println("linkedList=" + linkedList1);
        }
        //使用增强for循环
        System.out.println("===使用增强for循环===");
        for (Object o1 : linkedList) {
            System.out.println(o1);
        }
        System.out.println("===LinkedList遍历使用普通for循环===");
        for (int i = 0; i < linkedList.size(); i++) {
            System.out.println(linkedList.get(i));
        }
        //源码阅读
        //1. LinkedList linkedList = new LinkedList();
        /*
           public LinkedList() {}
           2.这时linkedList的属性 first=null last=null
           3.执行
           public boolean add(E e) {
                linkLast(e);
                return true;
            }
           4.将新的结点,加入到双向链表的最后
           void linkLast(E e) {
                final Node<E> l = last;
                final Node<E> newNode = new Node<>(l, e, null);
                last = newNode;
                if (l == null)
                    first = newNode;
                else
                    l.next = newNode;
                size++;
                modCount++;
            }
         */
        /*
            linkedList.remove();//这里默认删除是第一个结点
            1.执行的是
            public E remove() {
                    return removeFirst();
                }
            2.执行
            public E removeFirst() {
                final Node<E> f = first;
                if (f == null)
                    throw new NoSuchElementException();
                return unlinkFirst(f);
            }
            3.执行unlinkFirst,将f 指向的双向链表的第一个结点拿掉
            private E unlinkFirst(Node<E> f) {
                // assert f == first && f != null;
                final E element = f.item;
                final Node<E> next = f.next;
                f.item = null;
                f.next = null; // help GC
                first = next;
                if (next == null)
                    last = null;
                else
                    next.prev = null;
                size--;
                modCount++;
                return element;
            }
         */
    }
}

输出结果如下

linkedList=[1, 2, 3]
linkedList=[2, 3]
linkedList=[2, 99]
99
===LinkedList遍历使用迭代器===
linkedList=2
linkedList=99
===使用增强for循环===
2
99
===LinkedList遍历使用普通for循环===
2
99

ArrayList和LinkedList的比较


目录
相关文章
|
2月前
|
存储 安全 Java
【高薪程序员必看】万字长文拆解Java并发编程!(7):不可变类设计指南
🌟 ​大家好,我是摘星!​ 🌟今天为大家带来的是并发编程中Java不可变类设计指南,废话不多说让我们直接开始。
43 0
|
2月前
|
人工智能 安全 Java
Java并发包下Atomic相关类的使用
本文介绍了 `java.util.concurrent.atomic` 包下的各类原子类及其使用场景,包括基本类型原子类(如 `AtomicInteger`、`AtomicLong`)、数组类型原子类(如 `AtomicIntegerArray`)、引用类型原子类(如 `AtomicReference`)、对象属性修改原子类(如 `AtomicIntegerFieldUpdater`)以及原子操作增强类(如 `LongAdder` 和 `LongAccumulator`)。同时,详细对比了不同原子类在高并发场景下的性能表现,展示了 `LongAdder` 的高效性。
92 31
|
3月前
|
Java 数据安全/隐私保护
Java 类和对象
本文介绍了Java编程中类和对象的基础知识,作为面向对象编程(OOP)的核心概念。类是对象的蓝图,定义实体类型;对象是具体实例,包含状态和行为。通过示例展示了如何创建表示汽车的类及其实例,并说明了构造函数、字段和方法的作用。同时,文章还探讨了访问修饰符的使用,强调封装的重要性,如通过getter和setter控制字段访问。最后总结了类与对象的关系及其在Java中的应用,并建议进一步学习继承等概念。
|
3月前
|
Java
java中一个接口A,以及一个实现它的类B,一个A类型的引用对象作为一个方法的参数,这个参数的类型可以是B的类型吗?
本文探讨了面向对象编程中接口与实现类的关系,以及里氏替换原则(LSP)的应用。通过示例代码展示了如何利用多态性将实现类的对象传递给接口类型的参数,满足LSP的要求。LSP确保子类能无缝替换父类或接口,不改变程序行为。接口定义了行为规范,实现类遵循此规范,从而保证了多态性和代码的可维护性。总结来说,接口与实现类的关系天然符合LSP,体现了多态性的核心思想。
82 0
|
存储 缓存 网络协议
阿里云服务器通用型g5、g6、g7、g8y实例四代产品对比与选择参考
目前阿里云在售的通用型云服务器中,包含了第5代通用型g5、第6代通用型g6、第7代通用型g7和最新第八代通用型g8y等,有的新手用户并不清楚这四代产品之间的差别,下面以通用型g5、g6、g7、g8y实例在规格、CPU(核)、内存(G)、计算、存储、内存以及不同配置的指标数据等方面为大家做个对比,让大家了解一下他们之间的不同,以供参考与选择。
1613 0
阿里云服务器通用型g5、g6、g7、g8y实例四代产品对比与选择参考
|
9月前
|
数据采集 存储 监控
数据治理:解锁数据资产潜力,驱动企业决策与业务增长的密钥
在当今这个数据驱动的时代,企业所拥有的数据资产已成为其核心竞争力的重要组成部分。然而,仅仅拥有海量数据并不足以确保成功,关键在于如何有效地管理和利用这些数据,以支持精准决策、优化运营流程并推动业务持续增长。这就是数据治理的重要性所在——它是一套系统性的方法和流程,旨在确保数据质量、安全性、可用性和合规性,从而让数据资产能够最大化地支持企业决策和业务增长。
|
9月前
|
存储 分布式计算 大数据
大数据的工具都有哪些?
【10月更文挑战第9天】大数据的工具都有哪些?
848 1
|
机器学习/深度学习 算法 图计算
图机器学习入门:基本概念介绍
图机器学习是机器学习的分支,专注于处理图形结构数据,其中节点代表实体,边表示实体间关系。本文介绍了图的基本概念,如无向图与有向图,以及图的性质,如节点度、邻接矩阵。此外,还讨论了加权图、自循环、多重图、双部图、异构图、平面图和循环图。图在描述数据关系和特征方面具有灵活性,为机器学习算法提供了丰富的结构信息。
321 0
|
11月前
|
机器学习/深度学习 数据采集 人工智能
机器学习在医疗诊断中的应用:开启智慧医疗新时代
【8月更文挑战第5天】机器学习革新医疗诊断,提升精准度与效率。通过分析医学影像和基因数据,实现疾病早期检测与个性化治疗。在药物研发中,加速候选药物筛选与优化过程。智能化患者管理及智能辅助决策系统进一步增强医疗服务质量。面对数据质量和隐私保护挑战,持续技术创新推动智慧医疗发展。
|
网络协议 Linux
Linux网络管理之hostname命令 – 显示和设置系统的主机名
hostname命令用于显示和设置系统的主机名称。环境变量HOSTNAME也保存了当前的主机名。
1189 0
Linux网络管理之hostname命令 – 显示和设置系统的主机名