• List集合


    在介绍常见集合类之前先给大家看看这个UML图(就如同设计师需要看懂设计稿一样)

     注意:List、Set、Map没有实现同一个接口 Map是一个单独的接口。它是键值对类型先有键(主键)再有值的 

    什么是UML?

           UML是统一建模语言,是一种可视化面向对象建模语言,是一种用来对真实世界物理进行建模的标准标记,用图形方式表现典型的面向对象系统的整个结构。它的作用域不局限于支持面向对象的分析与设计,还支持从需求分析开始的软件开发的全过程。

    为了更好的看懂类图,大家可以点进下方链接了解了解UML类图几种关系的总结

    UML类图几种关系的总结http://www.uml.org.cn/oobject/201609062.asp

    List集合

    特点:元素有序,且可重复

    遍历:下标,foreach,迭代器

    1. List<Integer> list=new ArrayList<Integer>();
    2. @Before
    3. public void setup() {
    4. list.add(1);
    5. list.add(2);
    6. list.add(3);
    7. list.add(3);
    8. list.add(4);
    9. }
    10. /**
    11. * foreach遍历
    12. */
    13. @Test
    14. public void list01() {
    15. for(Integer e:list){
    16. System.out.println(e);
    17. }
    18. }
    19. /**
    20. * for循环
    21. */
    22. @Test
    23. public void list02() {
    24. for(int i=0;i<list.size();i++){
    25. System.out.println(list.get(i));
    26. }
    27. }
    28. /**
    29. * 迭代器
    30. */
    31. @Test
    32. public void list03() {
    33. Iterator<Integer> it = list.iterator();
    34. while(it.hasNext()) {
    35. System.out.println(it.next());
    36. }
    37. }

    扩容:

    1. 初始容量10,负载因子0.5,扩容增量0.5倍
    2. 新容量 = 原容量 + 原容量 * 0.5  , 如 ArrayList的容量为10,一次扩容后是容量为15

    代码示例:

    1. public void listKR()throws Exception {
    2. List<Integer> list=new ArrayList<Integer>();
    3. for(int i=0;i<=100;i++) {
    4. list.add(i);
    5. System.out.println("i :"+i);
    6. System.out.println("length :"+getListElsSize(list));
    7. }
    8. }
    9. private int getListElsSize(List obj)throws Exception {
    10. Class<? extends List> clazz = obj.getClass();
    11. Field f = clazz.getDeclaredField("elementData");
    12. f.setAccessible(true);
    13. Object[] object =(Object[]) f.get(obj);
    14. return object.length;
    15. }

    效果如下: 

    实现

    🟡ArrayList:是一个简单数据结构,具有超出容量自动扩容,动态数组的特点。内部实现是基于基础的对象数组的。随机访问快但是不适合随机增加或删除。线程不安全

    🟡LinkedList:LinkedList提供额外的get,remove,insert方法在LinkedList的首部或尾部。LinkedList可被用作堆栈(stack)【包括了push,pop方法】,队列(queue)或双向队列(deque)。适合做随机的增加或删除。以双向链表实现,链表无容量限制,允许元素为null,线程不安全

    🟡Vector:是线程安全的,但是并行性能慢,不建议使用

    🟡CopyOnWriteArrayList:写时复制出一个新的数组,完成插入、修改或者移除操作后将新数组赋值给array,适合于读多,写少的场景。比Vector性能高,最终一致性。实现了List接口,使用方式与ArrayList类似。线程安全


    ArrayList remove(删除) 的注意点 ❗❗❗

    题目要求:删除集合中所有为3的元素

    数据准备:为方便演示,需要有紧挨在一起的两个或多个相同的元素

    1. List<Integer> list=new ArrayList<Integer>();
    2. list.add(1);
    3. list.add(2);
    4. list.add(3);
    5. list.add(3);
    6. list.add(4);

    1️⃣第一种:for循环遍历list删除指定元素❎

    1. public void remove01() {
    2. for(int i=0;i<list.size();i++){
    3. if(list.get(i)==3)
    4. list.remove(i);
    5. }
    6. System.out.println(list);
    7. }

     效果图如下:

    很显然只删除了一个3,这是为什么呢?因为当删除到元素3的时候下面元素的位置会往上移那么原先第二个3的位置就成4了 所以没有删除成功

     图形解读:

     2️⃣第二种:for循环遍历list删除时将i--✅

    1. public void remove02() {
    2. for(int i=0;i<list.size();i++){
    3. if(list.get(i)==3)
    4. list.remove(i--);
    5. }
    6. System.out.println(list);
    7. }

     效果图如下:

    当删除第一个3时,3后面元素都会向上移动,而当前index等于2,后一个3会移除到index=2的位置,又因为index-1被跳回去了 所以删除成功!!!

    3️⃣第三种:倒序遍历list是✅

    1. public void remove03() {
    2. for(int i=list.size()-1;i>=0;i--){
    3. if(list.get(i)==3){
    4. list.remove(i);
    5. }
    6. }
    7. System.out.println(list);
    8. }

    效果图如下: 

     

    4️⃣第四种:forEach遍历list删除 ❎

    1. public void remove04() {
    2. for(Integer i:list){
    3. if(i==3) list.remove(i);
    4. }
    5. System.out.println(list);
    6. }

    效果图如下:

    报错显示:java.util.ConcurrentModificationException (当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。

    将方法点进去查看源码会发现在next、remove方法中都会调用checkForConmodification的方法。

    若modCount不等于expectedModCount 就会报ConcurrentModificationException

     但是在删除的时候是通过ArrayList的remove方法去操作的,不是Itr内部的那个删除方法去操作的。remove()函数会调用fastRemove()函数,使得modCount的值自增1.然而,for循环下一次调用Itr.next(),Itr.next()调用Itr.checkForComodification()时,会发现,modCount和expectedModCount两个值不相等!因为在这个删除操作的过程中没有对expectedModCount重新赋值,所以就抛出异常了。

    1. public boolean remove(Object o) {
    2. if (o == null) {
    3. for (int index = 0; index < size; index++)
    4. if (elementData[index] == null) {
    5. fastRemove(index);
    6. return true;
    7. }
    8. } else {
    9. for (int index = 0; index < size; index++)
    10. if (o.equals(elementData[index])) {
    11. fastRemove(index);
    12. return true;
    13. }
    14. }
    15. return false;
    16. }
    17. private void fastRemove(int index) {
    18. modCount++;
    19. int numMoved = size - index - 1;
    20. if (numMoved > 0)
    21. System.arraycopy(elementData, index+1, elementData, index,
    22. numMoved);
    23. elementData[--size] = null; // Let gc do its work
    24. }

    那为什么删除倒数第二个会成功呢?

    为了达到效果,在原本数据中添加一条数据

    1. List<Integer> list=new ArrayList<Integer>();
    2. list.add(1);
    3. list.add(2);
    4. list.add(3);
    5. list.add(3);
    6. list.add(5);
    7. list.add(4);

     方法

    1. public void remove04() {
    2. for(Integer i:list){
    3. if(i==5)
    4. list.remove(i);
    5. }
    6. System.out.println(list);
    7. }

    刚开始cursor开始值是默认为0,0不等于size为true,将会进入到next()方法中,cursor会加一,当执行到5的时候,cursor等于5,5被删除了,并且size从原本的6变为5了,这个时候cursor等于size,就不会进入next()方法了。

    1. 1.It gets the iterator.
    2. 2.Checks for hasNext().
    3. public boolean hasNext()
    4. {
    5. return cursor != size(); // cursor is zero initially.
    6. }
    7. 3.If true, gets the next element using next().
    8. public E next()
    9. {
    10. checkForComodification();
    11. try {
    12. E next = get(cursor);
    13. lastRet = cursor++;
    14. return next;
    15. } catch (IndexOutOfBoundsException e) {
    16. checkForComodification();
    17. throw new NoSuchElementException();
    18. }
    19. }
    20. final void checkForComodification()
    21. {
    22. // Initially modCount = expectedModCount (our case 5)
    23. if (modCount != expectedModCount)
    24. throw new ConcurrentModificationException();
    25. }

    5️⃣第五种:通过迭代器进行删除1✅

    1. public void remove05() {
    2. Iterator<Integer> it=list.iterator();
    3. while(it.hasNext()){
    4. if(it.next()==3){
    5. it.remove();
    6. }
    7. }
    8. System.out.println(list);
    9. }

    6️⃣第六种::通过迭代器进行删除2❎

    1. public void remove06() {
    2. Iterator<Integer> it=list.iterator();
    3. while(it.hasNext()){
    4. Integer value=it.next();
    5. if(value==3){
    6. list.remove(value);
    7. }
    8. }
    9. }

    效果图如下:

    报错显示:java.util.ConcurrentModificationException (当方法检测到对象的并发修改,但不允许这种修改时,抛出此异常。)原因查看第四种方法

    删除的参数是基本型的整数

    1. public void remove07() {
    2. list.remove(2);
    3. System.out.println(list);
    4. }

    效果图如下:

    若想删除对象类型的2  使用Integer.valueOf()   基本类型的2封装成对象类型的2

    1. public void remove07() {
    2. list.remove(Integer.valueOf(2));//基本类型的2封装成对象类型的2
    3. System.out.println(list);
    4. }

     效果图如下

  • 相关阅读:
    [Node]几个常用的node后端框架
    异构计算技术分析
    jenkins pipeline 通过withCredentials连接项目服务器进行自动部署
    萌新的FPGA学习绪论-1
    小白大白读论文-关于EfficientNetV2论文的 疑问 与 总结
    Charles的证书下载(web端)
    java里关于json数组和json的使用
    数学建模:运筹学中的主要问题(技术)
    “从部署到优化,打造高效会议管理系统“
    浅刷牛客链表题,逐步深入链表,理解链表
  • 原文地址:https://blog.csdn.net/weixin_62270300/article/details/125469281