基于java构造方法Vector删除元素源码分析

作者:叫我王员外就行 时间:2023-11-25 14:54:45 

(注意:本文基于JDK1.8) 

基于java构造方法Vector删除元素源码分析

基于java构造方法Vector删除元素源码分析

基于java构造方法Vector删除元素源码分析

前言

包括迭代器中的remove()方法,以及删除单个元素、删除多个元素、删除所有元素、删除不包含的所有元素的方法,Vector中共计10个对外的API可以用于删除元素,今天一起分析每一个删除元素的方法是如何实现的!

remove(int)方法分析


   public synchronized E remove(int index) {
       modCount++;
       if (index >= elementCount)
           throw new ArrayIndexOutOfBoundsException(index);
       E oldValue = elementData(index);
       int numMoved = elementCount - index - 1;
       if (numMoved > 0)
           System.arraycopy(elementData, index+1, elementData, index,
                            numMoved);
       elementData[--elementCount] = null; // Let gc do its work

return oldValue;
   }

用于删除指定下标单个元素的方法,传入的参数index表示元素的下标,第一个元素的下标是0,这个基础知识点不要忘记哦

1、为fail-fast机制保驾护航

modCount是Vector对象持有的一个int变量,它本身位于Vector的父类AbstractList中,此处增加1,表示Vector的元素状态发生改变,迭代器那里会使用fail-fast,防止多线程下即遍历又删除,也防止单线程下,一边遍历元素、一边删除元素

2、检查下标是否存在元素

检查传入的下标index是否存在元素,当index与elementCount相等或者大于elementCount,此处的index并没有元素,所以不能删除没有元素的位置,此处作者抛出ArrayIndexOutOfBoundsException对象,为此告知调用者,你传入的下标根本没有元素,怎么删除呢?

3、保存删除的元素到局部变量

调用elementData元素,并传入下标index,获得指定下标处的元素,并由局部变量oldValue负责保存

4、计算需要挪动元素的数量

使用表示元素总数的elementCount减去index、减去1,得到需要挪动元素的数量并存储到局部变量numMoved

5、挪动元素

如果需要挪动元素,就将index下标后面的所有元素向前挪动(复制)

6、减少元素总数值

先将元素总数elementCount减去1

7、将持有元素的引用,赋值为null

将Vector对象持有的数组elementData对象的指定下标处,赋值为null,GC会删除没有Root结点对象连接的对象

8、向调用者返回删除后的元素

return会返回此时被删除的元素对象

remove(Object)方法分析


   public boolean remove(Object o) {
       return removeElement(o);
   }

用于将第一个匹配的元素对象删除的方法,传入的参数为元素对象,此方法并没有使用synchronized修饰,那么它如何保证线程安全的删除元素呢?往下看……

1、实际调用removeElement()方法

2、向调用者返回删除结果

removeElement(Object)方法分析


   public synchronized boolean removeElement(Object obj) {
       modCount++;
       int i = indexOf(obj);
       if (i >= 0) {
           removeElementAt(i);
           return true;
       }
       return false;
   }

用于删除元素的方法,使用synchronized修饰,同一时刻只有获得对象锁的线程可以执行该方法,未获得对象锁的线程,将被阻塞在方法的入口处,传入的1个参数表示元素对象

1、fail-fast机制保护

modCount增加1,表示Vector持有的元素发生改变

2、获取元素对象在数组中的下标

调用index()方法,同时会将元素对象ob传入进去,返回值则由局部变量i负责存储,它存储的是元素在数组中下标

3、元素存在,则继续执行删除工作

当局部变量i的值大于等于0,说明元素存储在数组中(Vector对象持有一个数组对象,用于保存元素的引用),通过调用removeElement()方法完成删除工作,最后向调用者返回true,表示删除元素成功

4、当元素不存在时,向调用者返回false

removeElementAt(int)方法分析


   public synchronized void removeElementAt(int index) {
       modCount++;
       if (index >= elementCount) {
           throw new ArrayIndexOutOfBoundsException(index + " >= " +
                                                    elementCount);
       }
       else if (index < 0) {
           throw new ArrayIndexOutOfBoundsException(index);
       }
       int j = elementCount - index - 1;
       if (j > 0) {
           System.arraycopy(elementData, index + 1, elementData, index, j);
       }
       elementCount--;
       elementData[elementCount] = null; /* to let gc do its work */
   }

用于删除指定下标的元素,使用synchronized修饰,同一时刻只有1个线程可以执行该方法,其它未获得对象锁的线程将被阻塞在入口处,传入的1个参数index表示元素的下标

1、fail-fast机制

modCount增加1,表示Vector保存的元素发生改变

2、检查下标是否合理

当传入的下标index大于等于Vector对象持有的elementCount值时,抛出ArrayIndexOutOfBoundsException,告知调用者,index >= xx值

当传入的下标index小于0时,同样抛出ArrayIndexOutOfBoundsException对象,此时只告知index值是多少

只有下标0至elementCount - 1的范围内,才有元素,所以作者的保护相当的合理

3、计算需要移动元素的数量

比如一共保存了5个元素(elementCount)、需要删除下标为3的元素,下标为3的元素是第4个元素,后续需要挪动的元素数量为1,所以

公式为:remove_num = elementCount - index - 1,我们再套进来公式里:remove_num = 5 - 3 - 1

4、开始挪动元素

挪动元素,而采用的是复制元素,system类的静态方法arrycopy即可做到,它接受5个参数

第一个参数:表示需要从哪个数组对象中复制元素(源头)

第二个参数:表示需要从数组对象的哪个下标处,开始复制

第三个参数:表示需要粘贴到哪个数组对象中(目标)

第四个参数:表示需要粘贴到数组对象的起始下标

第五个参数:表示共计复制几个元素

5、记录的元素总数减去1

elementCount减少1

6、将剩下的数组中,多余的引用,删除掉

因为每个元素都向前复制了一位,所以此时的elementCount指向的下标处,还存着对象的引用,这会造成对象无法被GC回收,赋值为null,由GC回收对象占用的内存空间

removeIf()方法分析


   public synchronized boolean removeIf(Predicate<? super E> filter) {
       Objects.requireNonNull(filter);
       // figure out which elements are to be removed
       // any exception thrown from the filter predicate at this stage
       // will leave the collection unmodified
       int removeCount = 0;
       final int size = elementCount;
       final BitSet removeSet = new BitSet(size);
       final int expectedModCount = modCount;
       for (int i=0; modCount == expectedModCount && i < size; i++) {
           @SuppressWarnings("unchecked")
           final E element = (E) elementData[i];
           if (filter.test(element)) {
               removeSet.set(i);
               removeCount++;
           }
       }
       if (modCount != expectedModCount) {
           throw new ConcurrentModificationException();
       }

// shift surviving elements left over the spaces left by removed elements
       final boolean anyToRemove = removeCount > 0;
       if (anyToRemove) {
           final int newSize = size - removeCount;
           for (int i=0, j=0; (i < size) && (j < newSize); i++, j++) {
               i = removeSet.nextClearBit(i);
               elementData[j] = elementData[i];
           }
           for (int k=newSize; k < size; k++) {
               elementData[k] = null;  // Let gc do its work
           }
           elementCount = newSize;
           if (modCount != expectedModCount) {
               throw new ConcurrentModificationException();
           }
           modCount++;
       }
       return anyToRemove;
   }

实现Collection接口的方法,用于根据指定条件删除元素的方法,同样由synchronized修饰,同一时刻只有获取到当前对象锁的线程可以调用此方法,其它线程如果也调用此方法,会被阻塞在方法的入口处

1、检查传入的Predicate对象

确保Predicate对象必须传入,此处使用Objects的静态方法requireNonNull()检查

2、创建用于记录删除数量的局部变量

removeCount,默认值为0

3、临时存储当前Vector对象持有的元素总数

创建一个局部变量size用于存储当前元素总数elementCount

4、创建BitSet对象

利用Vector对象持有的元素总数size,用于创建一个BitSet对象,局部变量removeSet临时指向该此BitSet对象

removeAllElement()方法分析


   public synchronized void removeAllElements() {
       modCount++;
       // Let gc do its work
       for (int i = 0; i < elementCount; i++)
           elementData[i] = null;
        elementCount = 0;
   }

用于删除Vector对象持有的所有元素对象

1、fail-fast机制保护

实例变量modCount增加1,表示Vector持有的元素发生变化

2、遍历数组对象

将Vector对象持有的数组对象elementData中实际保存元素对象引用的所有位置,全部赋值为null,当对象从GC Roots处不可达时,垃圾收集器会回收对象占用的内存空间

3、元素总数标记为0

Vector对象持有的elementCount标记为0,说明Vector对象不再持有任何元素 

removeAll(Collection)方法分析


   public synchronized boolean removeAll(Collection<?> c) {
       return super.removeAll(c);
   }

用于删除多个元素的方法,只有与传入的Collection对象中持有的元素匹配的元素会被删除

1、直接调用父类的removeAll()方法,并将传入的Collection对象传入进去

2、向调用者返回删除元素的结果

父类中的removeAll(Collection)方法分析


   public boolean removeAll(Collection<?> c) {
       Objects.requireNonNull(c);
       boolean modified = false;
       Iterator<?> it = iterator();
       while (it.hasNext()) {
           if (c.contains(it.next())) {
               it.remove();
               modified = true;
           }
       }
       return modified;
   }

位于父类AbstractCollection中,用于删除与传入参数Collection对象中匹配的所有元素

1、检查传入参数Collection对象

2、定义局部变量,表示是否修改,默认值false

3、调用iterator()方法获取迭代器对象,并由局部变量it负责保存

此iterator()方法都是子类去实现,Vector中也实现了该方法,此方法会返回一个迭代器对象

4、使用迭代器对象的方法进行遍历与删除

hasNext()方法用于判断是否有下一个元素,当第一次使用时,判断的是第一个元素

next()方法可以获取到一个元素,第一次使用时,获取到的是第一个元素

remove()方法可以删除一个元素

每当删除一个元素(Vector中持有的元素与Collection中的某个元素相同),将是否修改的标志位modified赋值为true

5、向调用者返回删除结果 

retainAll(Collection)方法分析


   public synchronized boolean retainAll(Collection<?> c) {
       return super.retainAll(c);
   }

用于删除除了传入的Collection对象持有的元素之外的所有元素,求交集……

来源:https://blog.csdn.net/cadi2011/article/details/115424110

标签:构造方法,Vector,删除元素
0
投稿

猜你喜欢

  • Unity使用摄像机实现望远镜效果

    2021-06-07 23:30:26
  • Android 沉浸式状态栏及悬浮效果

    2023-07-29 23:03:15
  • Android仿直播类app赠送礼物功能

    2023-07-26 05:06:17
  • 详解Java中Collections.sort排序

    2023-08-20 00:51:48
  • 通过LinQ查询字符出现次数的实例方法

    2023-12-10 13:40:01
  • java 中http请求为了防止乱码解决方案

    2023-08-09 07:59:33
  • C#开发微信门户及应用(4) 关注用户列表及详细信息管理

    2023-06-05 07:40:43
  • Android 自定义圆形带刻度渐变色的进度条样式实例代码

    2023-11-23 13:21:38
  • Android应用借助LinearLayout实现垂直水平居中布局

    2023-02-05 01:46:45
  • Java RabbitMQ高级特性详细分析

    2021-12-26 00:31:36
  • 详解androidstudio项目上传到github方法以及步骤

    2023-07-15 02:55:42
  • Android集成腾讯X5实现文档浏览功能

    2023-10-03 23:44:06
  • 如何使用IDEA的groovy脚本文件生成带JPA注解的实体类(图文详解)

    2022-02-04 02:42:04
  • c# 以二进制读取文本文件

    2023-02-28 15:23:26
  • Android Handler runWithScissors 梳理流程解析

    2023-01-29 11:51:27
  • 简单实现Android闹钟功能

    2022-05-23 16:17:53
  • 聊聊在Servlet中怎么上传文件

    2022-03-07 17:56:44
  • C#实现简单串口通讯实例

    2022-06-18 11:29:42
  • Android Compose实现联系人列表流程

    2023-09-25 00:50:04
  • Java代码块与代码加载顺序原理详解

    2023-06-03 12:56:42
  • asp之家 软件编程 m.aspxhome.com