List集合-CSDN博客

List集合

集合分为单列,双列

ArrayList

ArrayList 类是一个可以动态修改的数组,与普通数组的区别就是它是没有固定大小的限制,我们可以添加或删除元素。

优点:
动态增长:ArrayList 可以根据需要自动增长和缩减大小,这使得它非常灵活,适用于元素数量不确定的场景。
索引访问:可以通过索引快速访问和修改元素,这使得 ArrayList 在需要频繁访问和修改元素的场景中非常高效。
易于使用:ArrayList 提供了丰富的 API,使得它易于使用和操作。
线程不安全:ArrayList 不是线程安全的,这意味着在多线程环境下,如果没有适当的同步措施,可能会出现线程安全问题。但是,这也使得 ArrayList 在单线程环境中执行效率更高。
缺点:
线程不安全:如前所述,ArrayList 不是线程安全的,这在多线程环境中可能会导致问题。
性能开销:虽然 ArrayList 提供了动态增长的功能,但这也带来了一定的性能开销。每次增长或缩减大小都需要重新分配和复制数组,这在元素数量非常大时可能会影响性能。
不适合大量插入和删除:由于 ArrayList 底层使用数组实现,因此在大量插入和删除元素时,可能需要移动大量元素,这会影响性能

添加元素  add
public class ArrayListDetail01 {
    public static void main(String[] args) {
        // ArrayList 是线程不安全的(执行效率高)
        // 基本等同于Vector
        ArrayList<Integer> myNumbers = new ArrayList<Integer>();
        myNumbers.add(33);
        myNumbers.add(15);

        myNumbers.add(3, 100); 
        System.out.println(myNumbers);

    }
}

add(element)

add(index,element) 这里如果index大于已有元素+1会报异常

访问元素 get

访问 ArrayList 中的元素可以使用 get() 方法

public class ArrayListDetail01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("null");
        arrayList.add("jack");
        arrayList.add("");
        arrayList.add(11);
        arrayList.add(null);
        System.out.println(arrayList);
        System.out.println(arrayList.get(1));
    }
}
修改元素

如果要修改 ArrayList 中的元素可以使用 set() 方法, set(int index, E element) 方法的第一个参数是索引(index),表示要替换的元素的位置,第二个参数是新元素(element),表示要设置的新值

public class ArrayListDetail01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("null");
        arrayList.add("jack");
        arrayList.add("");
        arrayList.add(11);
        arrayList.add(null);
        System.out.println(arrayList);
        System.out.println(arrayList.get(1));
        arrayList.set(3,"我是空");
        System.out.println(arrayList);
    }
}
删除元素

如果要删除 ArrayList 中的元素可以使用 remove() 方法:

public class ArrayListDetail01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("null");
        arrayList.add("jack");
        arrayList.add("");
        arrayList.add(11);
        arrayList.add(null);
        System.out.println(arrayList);
        System.out.println(arrayList.get(1));
        arrayList.set(3,"我是空");
        System.out.println(arrayList);
        arrayList.remove(3);
        System.out.println(arrayList);
    }
}
计算大小

如果要计算 ArrayList 中的元素数量可以使用 size() 方法:

public class ArrayListDetail01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("null");
        arrayList.add("jack");
        arrayList.add("");
        arrayList.add(11);
        arrayList.add(null);
        System.out.println(arrayList);
        System.out.println(arrayList.get(1));
        arrayList.set(3,"我是空");
        System.out.println(arrayList);
        arrayList.remove(3);
        System.out.println(arrayList);
        System.out.println(arrayList.size());
    }
}

迭代数组列表

我们可以使用 for 来迭代数组列表中的元素:
public class ArrayListDetail01 {
    public static void main(String[] args) {
        ArrayList arrayList = new ArrayList();
        arrayList.add("null");
        arrayList.add("jack");
        arrayList.add("");
        arrayList.add(11);
        arrayList.add(null);
        for (int i = 0; i < arrayList.size(); i++) {
            System.out.println(arrayList.get(i));
        }
    }
}也可以使用 for-each 来迭代元素
for (Object arrayList1: arrayList) {
    System.out.println(arrayList1);
}
foreach

其他的引用类型

ArrayList 中的元素实际上是对象,在以上实例中,数组列表元素类型不同,所有foreach中要用Object,如果都是String 用String。

如果我们要存储其他类型,而 <E> 只能为引用数据类型,这时我们就需要使用到基本类型的包装类。

public class ArrayListDetail01 {
    public static void main(String[] args) {
        // ArrayList 是线程不安全的(执行效率高)
        // 基本等同于Vector
        ArrayList<Integer> arrayList = new ArrayList<>();
        arrayList.add(1);
        arrayList.add(2);
这里会报错
      //  arrayList.add(new Integer(1)
for (Integer a : arrayList){
    System.out.println(a);
}
    }
}

报错原因如下

在Java中,ArrayList 是一个泛型类,这意味着你可以指定它将存储的元素类型。当你创建一个 ArrayList 时,你应该指定你想要存储的元素类型,例如 ArrayList<Integer> 表示这个 ArrayList 将存储 Integer 类型的元素。
在你的代码中,你创建了一个 ArrayList<Integer>,这意味着这个 ArrayList 应该存储 Integer 类型的元素。然而,在你添加元素时,你使用了 arrayList.add(1) 和 arrayList.add(2),这是正确的,因为 1 和 2 是 int 类型,它们会自动装箱为 Integer 类型并添加到 ArrayList 中。
但是,当你使用 arrayList.add(new Integer(1)) 时,你显式地创建了一个新的 Integer 对象并将其添加到 ArrayList 中。这在Java 5及以后的版本中是不必要的,因为Java会自动将基本类型(如 int)装箱为对应的包装类型(如 Integer)。因此,你可以直接使用 arrayList.add(1) 而不是 arrayList.add(new Integer(1))

Integer d = new Integer(1); 这段代码也会报错

在Java中,Integer d = new Integer(1); 这行代码在Java 9及以后的版本中会报错,因为Integer(int)构造函数已经被标记为过时(deprecated),并在未来的版本中可能会被移除。这是因为Java推荐使用自动装箱和拆箱机制来处理基本类型和包装类型之间的转换,而不是直接使用构造函数。
如果你使用的是Java 9或更高版本,你应该使用自动装箱来创建Integer对象,例如:Integer d = 1;。这样,Java编译器会自动将基本类型int的值1装箱为Integer对象。
如果你使用的是Java 8或更早的版本,Integer d = new Integer(1); 这行代码不会报错,但是它会生成一个警告,提示你这个构造函数已经被标记为过时。你可以忽略这个警告,但是建议你更新你的代码以使用现代的Java特性。
在你的代码中,如果你是在Java 9或更高版本中编写的,你应该将Integer d = new Integer(1); 改为Integer d = 1;。如果你是在Java 8或更早的版本中编写的,你可以保留这行代码,但是建议你添加一个注释来解释为什么你使用了过时的构造函数,并且计划在未来更新你的代码

这里我使用的是jdk17

如果使用jdk1.8,上面的报错信息也就没有了

排序
对字符串排序
public class ArrayListDetail01 {
    public static void main(String[] args) {
 
        ArrayList<String> sites = new ArrayList<String>();
        sites.add("Taobao");
        sites.add("Wiki");
        sites.add("Runoob");
        sites.add("Weibo");
        sites.add("Google");
          Collections.sort(sites);// 字母排序
        for (String i : sites) {
            System.out.println(i);
        }
    }
}
对数字排序
public class ArrayListDetail01 {
    public static void main(String[] args) {
        ArrayList<Integer> myNumbers = new ArrayList<Integer>();
        myNumbers.add(33);
        myNumbers.add(15);
        myNumbers.add(20);
        myNumbers.add(34);
        myNumbers.add(8);
        myNumbers.add(12);
        Collections.sort(myNumbers);  // 数字排序

        for (int i : myNumbers) {
            System.out.println(i);
        }
    }
}
arraylist底层原理

第一次创建默认大小是10

Default initial capacity.

transient Object[] elementData; // non-private to simplify nested class access

这段代码描述了ArrayList类中的一个重要属性:elementData。elementData是一个对象数组,用于存储ArrayList中的元素。ArrayList的容量就是这个数组的长度。
代码中提到,如果ArrayList是空的,并且其elementData属性等于DEFAULTCAPACITY_EMPTY_ELEMENTDATA,那么当第一个元素被添加到ArrayList时,它的容量将被扩展到DEFAULT_CAPACITY。DEFAULT_CAPACITY是一个静态常量,其值为10,这意味着一个新创建的空ArrayList在添加第一个元素之前,它的内部数组容量为0,但一旦添加了第一个元素,它的容量将自动扩展到10。
这种设计允许ArrayList在开始时使用最小的内存空间,并且只在需要时增加其容量,从而提高了内存使用效率。同时,它也确保了ArrayList在添加元素时具有足够的空间,避免了频繁的数组扩容操作,这可能会影响性能。

 ArrayList 是线程不安全的(执行效率高)
基本等同于Vector
Array 中维护了一个 Object类型的数组 elementData
transient Object[] elementData
当创建ArrayList对象时,如果使用无参构造器,则elementData为0
第一次添加 ,扩容为10,每次扩容1.5倍
如果是指定大小构造器,初始容量为指定大小,往后1.5倍扩容·
这里有待提升!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

LinkedList

LinkedList 是 Java 集合框架中的一个类,它实现了 List 接口和 Deque 接口,提供了双向链表的功能。LinkedList 可以存储重复元素,并且可以通过索引访问和修改元素。

优点:
动态增长:LinkedList 可以根据需要自动增长和缩减大小,这使得它非常灵活,适用于元素数量不确定的场景。
插入和删除效率高:在 LinkedList 中插入和删除元素的效率非常高,因为它只需要修改指针,而不需要移动元素。
内存使用效率高:LinkedList 的内存使用效率比 ArrayList 高,因为它不需要预先分配连续的内存空间。
线程不安全:LinkedList 不是线程安全的,这意味着在多线程环境下,如果没有适当的同步措施,可能会出现线程安全问题。但是,这也使得 LinkedList 在单线程环境中执行效率更高。

缺点:
随机访问效率低:由于 LinkedList 是通过链表实现的,因此随机访问元素的效率较低,需要从头开始遍历链表。
不适合大量随机访问:如果需要频繁地随机访问元素,LinkedList 不是一个好的选择,因为它的性能会随着元素数量的增加而下降。
实现复杂:LinkedList 的实现比 ArrayList 复杂,因为它需要维护链表的指针。

与 ArrayList 相比,LinkedList 的增加和删除的操作效率更高,而查找和修改的操作效率较低。

LinkedList 继承了 AbstractSequentialList 类。

LinkedList 实现了 Queue 接口,可作为队列使用。

LinkedList 实现了 List 接口,可进行列表的相关操作。

LinkedList 实现了 Deque 接口,可作为队列使用。

LinkedList 实现了 Cloneable 接口,可实现克隆。

LinkedList 实现了 java.io.Serializable 接口,即可支持序列化,能通过序列化去传输。

添加
public class LinkedListCRUD {
    public static void main(String[] args) {
     LinkedList<String> sites = new LinkedList<>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
        System.out.println(sites);
    }
}
在表头添加元素 addFirst()
public class LinkedListCRUD {
    public static void main(String[] args) {
     LinkedList<String> sites = new LinkedList<>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
        sites.addFirst("ddd");
        System.out.println(sites);
    }
}
在表尾添加元素 addLast()
public class LinkedListCRUD {
    public static void main(String[] args) {
     LinkedList<String> sites = new LinkedList<>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
        sites.addFirst("ddd");
        sites.addLast("xxx");
        System.out.println(sites);
    }
}
删除元素

remove()

removeFirst()

removeLast()

public class LinkedListCRUD {
    public static void main(String[] args) {
     LinkedList<String> sites = new LinkedList<>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
        sites.remove();
        sites.removeFirst();
        sites.removeLast();
        System.out.println(sites);
    }
}
查找    get(index)  getFirst()  getLast()
public class LinkedListCRUD {
    public static void main(String[] args) {
     LinkedList<String> sites = new LinkedList<>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
        System.out.println(sites.get(2));
        System.out.println(sites.getFirst());
        System.out.println(sites.getLast());
    }
}
遍历方式
public class LinkedListCRUD {
    public static void main(String[] args) {
     LinkedList<String> sites = new LinkedList<>();
        sites.add("Google");
        sites.add("Runoob");
        sites.add("Taobao");
        sites.add("Weibo");
       for (int size = sites.size(), i = 0; i < size; i++) {
            System.out.println(sites.get(i));
        }
        System.out.println("======================");
        Iterator<String> iterator = sites.iterator();
        while (iterator.hasNext()) {
            System.out.println(iterator.next());
        }
        System.out.println("======================");
        for (String site : sites) {
            System.out.println(site);
        }
    }
}
底层源码


LinkedList 的底层数据结构是双向链表,每个节点(Node)包含三个部分:元素值(element)、指向前一个节点的引用(prev)和指向后一个节点的引用(next)。
以下是 LinkedList 中 Node 类的定义:

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

    Node(E element, Node<E> next, Node<E> prev) {
        this.element = element;
        this.next = next;
        this.prev = prev;
    }
}


双向链表原理
双向链表是一种链表,其中每个节点都包含两个引用,一个指向前一个节点,另一个指向后一个节点。这种结构允许在链表中进行高效的插入和删除操作,因为只需要修改相邻节点的引用即可。
在 LinkedList 中,添加元素时,会创建一个新的 Node 节点,并将其插入到链表的适当位置。如果是在链表的头部添加元素,则新节点的 next 引用指向原来的头节点,原来的头节点的 prev 引用指向新节点;如果是在链表的尾部添加元素,则新节点的 prev 引用指向原来的尾节点,原来的尾节点的 next 引用指向新节点;如果是在链表的中间添加元素,则新节点的 prev 引用指向插入位置之前的节点,next 引用指向插入位置之后的节点,同时插入位置之前的节点的 next 引用和插入位置之后的节点的 prev 引用都指向新节点。
删除元素时,只需要修改被删除节点的前一个节点的 next 引用和后一个节点的 prev 引用,使其指向彼此即可。

vector

vector和arraylist相似,不过是线程安全

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值