java的list总结

集合的类图关系:

什么是集合,为什么需要:

可以用来存储数据,扩展了数组的功能, 数组和集合存储引用数据类型,存的都是地址值

 数组长度是固定,当添加的元素超过了数组的长度时需要对数组重新定义,太麻烦,java内部给我们提供了集合类,能存储任意对象,长度是可以改变的,随着元素的增加而增加,随着元素的减少而减少 

List

ArrayList

ArrayList 数据结构:底层实现是object数组(动态数组,可以扩容),它的随机访问速度极快,但是插入和删除的操作需要移动数组中的元素,比较麻烦。

  1. 它在没有初始化长度的时候,默认长度是10
  2. 如果向ArrayLIst添加元素,超过了原来的容量,那么扩容方案:扩容到原数组的1.5倍,如果扩容完之后还是小于mincapacity(最小容量),就扩容到mincapacity。宗旨就是将新加入的元素,能够放置到数组中
  3. ArrayList是线程不安全的,在多线程的情况下不要使用

Arraylist添加元素的原理

0、创建一个初始化长度的数组,若没有初始化长度的时候,不是在初始化Arraylist就创建好数组,而是在第一次add时创建

1、调用add方法,在插入数据之前,先要判断数组是否能够容下元素(调用方法参数是size+1,是当前数组中所有存在元素+1,也就是所需的最小容量(mincapacity,可能是批量添加)),容纳不下的话,此时要判断是空数组还是自定义长度数组,如果是空数组先判断mincapacity和默认数组长度10谁大,谁大就创建大的容量数组;进行第二步的扩容。

2、扩容:先根据原来的数组的长度,进行扩容到原来数组长度的1.5倍。如果扩容之后的容量小于mincapacity,则将mincapacity赋值给新数组的容量。如果扩容之后的容量大于数组定义最大容量,那么赋值给新数组Integer.MAX_VALUE-8

3、调用copyof方法,新建了一个数组,将原数组的对象复制到新的数组中,并且将现有的引用指向新的数组。

4、在调用element[size++]=e添加元素

arraylist add(index,E element)在某个位置添加元素实现

首先判断下标是否越界,检查当前容量是否可以容下一个元素,不够则扩容

通过arraycopy方法将elementdata从index开始将后面的元素往后移一位,在指定下标位置添加元素

arraylist get(int index)方法
功能:返回指定下标的元素
调用get(index)方法,之后先检查index的值是否大于Arraylist的大小
如果超过arraylist大小,会抛出异常,index<0了,系统会抛出异常
返回指定下标的元素

Linkedlist:

LinkedList 数据结构:双向链表 随机访问速度慢,查找元素是从头开始一个一个查找,但是适合于频繁的插入和删除操作。线程不安全

LinkedList内部实现原理:是一个Entry内部类,它包含了前一个元素的地址引用和后一个元素的地址引用,类似C语言的指针。进行操作元素

linkedlist的add方法添加元素的操作:

LInkedList添加操作时每个新添加的对象都会被放到新建的Node对象中,Node对象中包含加入的对象和前后指针属性(pred和next,pred和next其实都是Node对象,直接存放的就是当前对象的前一个节点对象和后一个节点对象,pred为最后一个及节点的next值为null)-》将last(指向最后一个节点)赋值为该节点-》判断最近一次last是否等于null-》若等于null将first(指向第一个节点)赋值到该节点-》若last不为null将原来最近一次last节点的next指针指向新加入的对象。

linkedlist的get方法,查询元素:

判断给定的索引值,若索引值大于整个链表长度的一半,则从后往前找,若索引值小于整个链表的长度的一般,则从前往后找。 这样就可以保证,不管链表长度有多大,搜索的时候最多只搜索链表长度的一半就可以找到,大大提升了效率。

list删除

正确的删除方式
  1. 使用Iterator进行删除
    当使用Iterator遍历List时,应该使用Iteratorremove()方法来删除元素,而不是使用Listremove()方法。

    Iterator<String> iterator = list.iterator();
    while (iterator.hasNext()) {
    String item = iterator.next();
    if (someConditionToRemove(item)) {
    iterator.remove();
    }
    }
  2. 使用List的remove()方法(通过索引)
    如果你知道要删除元素的索引,可以使用Listremove(int index)方法。

     

    java复制代码

    list.remove(index);

    注意:删除元素后,后续元素的索引会发生变化。

  3. 使用List的remove()方法(通过对象)
    如果List中没有重复元素,你可以使用Listremove(Object o)方法根据元素的值进行删除。

     

    java复制代码

    list.remove(element);

    注意:这个方法只会删除第一个匹配的元素(如果有多个)。

  4. 使用Java 8的removeIf()方法(仅对Collection接口中的removeIf方法,它在List接口中没有直接定义,但可以通过继承Collection接口的类使用,比如ArrayListLinkedList):
    如果你的列表是一个支持removeIf的集合(比如ArrayListLinkedList),你可以使用Java 8引入的removeIf方法。

     

    java复制代码

    list.removeIf(item -> someConditionToRemove(item));
错误的删除方式
  1. 在for-each循环中直接使用List的remove()方法
    这是一个常见的错误,因为for-each循环(也称为增强的for循环)在语法上不允许在循环体中修改集合的大小。

     

    java复制代码

    // 错误的方式
    for (String item : list) {
    if (someConditionToRemove(item)) {
    list.remove(item); // 这会引发ConcurrentModificationException
    }
    }

    这个错误会导致ConcurrentModificationException,因为for-each循环内部使用了一个迭代器来遍历集合,而直接在循环体内调用Listremove()方法会修改集合的状态,从而与迭代器发生冲突。

  2. 在for循环中通过索引删除元素时未更新索引
    如果在for循环中通过索引删除元素,并且没有相应地更新索引,可能会导致跳过某些元素或引发IndexOutOfBoundsException

     

    java复制代码

    // 错误的方式,可能会导致问题
    for (int i = 0; i < list.size(); i++) {
    if (someConditionToRemove(list.get(i))) {
    list.remove(i); // 删除后应该更新i,否则可能会跳过下一个元素
    }
    }

    为了避免这个问题,可以在删除元素后将索引i减1,或者从后往前遍历列表并删除元素。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值