基于java构造方法Vevtor添加元素源码分析

目录
  • 前言
  • add(E)方法分析
  • add(int,E)方法分析
  • insertElementAt()方法分析
  • addElement()方法分析
  • addAll()方法分析
  • addAll(int,Collection)方法分析
  • ListItr中的add()方法分析
  • 总结

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

前言

算上迭代器的add()方法,Vector中一共有7个添加元素的方法,5个添加单个元素的方法,2个添加多个元素的方法,接下来就一起分析它们的实现……Vector是一个线程安全的容器类,它的添加功能是如何做到线程安全的呢?

add(E)方法分析

    public synchronized boolean add(E e) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = e;
        return true;
    }

用于添加1个元素的方法,由synchronized修饰,只有获得对象锁的线程才可以执行该方法,其它未获得对象锁的线程会blocked在方法的入口处,等待已经持有对象锁的线程释放对象锁,传入的参数为即将要添加的元素对象,类型为指定的类型参数E

1、首先修改modCount值

Vecotor的父类AbstractList中,定义了实例变量modCount,这意味着每个Vector对象也持有一个modCount,这里将其+1,表示当前Vector对象持有的元素发生变化,这个modCount值是用于防止用户在多线程下使用容器类而设计的,常被称为fail-fast机制,可Vector本身是线程安全的容器类,为何这里还在使用modCount做++呢?费解……

2、然后检查底层数组容量能否再添加一个新的元素

通过调用ensureCapacityHelper()方法检查,传入参数是实际元素总数+1后的一个值,用于确认当前数组的容量是否需要扩充容量,如果数组的容量无法再添加一个新的元素,则在此方法中会对当前Vector对象持有的数组对象进行容量扩充(扩容的方法,将在单独的文章中分析,这里只需知道,容量不够,先扩容)

3、将元素赋值到数组对象中某个下标处,并增加表示元素总数的实例变量

先使用Vector对象持有的elmentCount作为数组下标,将新增加的元素赋值给elementData数组中对应的下标处,接着将表示实际持有元素的总数值的elementCount增加1,这里的实例变量elementCount同时扮演着两个角色,一个是用于记录Vector对象实际持有的元素总数,另一个是用于作为Vector对象持有的底层数组对象的下标!

4、返回添加元素的结果

每次都会返回true,表示添加元素成功

add(int,E)方法分析

    public void add(int index, E element) {
        insertElementAt(element, index);
    }

用于在指定下标处添加一个元素的方法,第一个参数index表示指定的下标,第二个参数element表示添加的元素

方法体中调用insertElementAt()方法,并将传入的index、element两个参数同时传入insertElementAt()方法中,由insertElementAt()方法完成元素的添加

insertElementAt()方法分析

    public synchronized void insertElementAt(E obj, int index) {
        modCount++;
        if (index > elementCount) {
            throw new ArrayIndexOutOfBoundsException(index
                                                     + " > " + elementCount);
        }
        ensureCapacityHelper(elementCount + 1);
        System.arraycopy(elementData, index, elementData, index + 1, elementCount - index);
        elementData[index] = obj;
        elementCount++;
    }

用于在指定下标处添加1个元素的方法,第一参数obj表示添加的元素对象,第二个参数index表示指定的下标……(注意:这里的参数顺序,真是老外思路),同样由synchronized修饰,只有获取到对象锁的线程才能执行该方法,未获取到对象锁的线程处于方法入口处,并处于blocked状态

1、最先修改modCount值

实例变量modCount定义在父类AbstractList中,它用于防止容器类在多线程下使用,常称为fail-fast机制i,此处将该值增加1,表示Vector对象持有的元素发生改变

2、检查传入的下标值是否合法

如果传入的下标值index大于Vector对象实际持有的元素总数elementCount值,此时抛出ArrayIndexOutOfBoundsException对象,并提示用户"index > elementCount"(替换为实际值)

3、检查是否需要扩容

调用ensureCapacityHelper()方法,同时将elementCount+1的值传了进去

4、拷贝数组元素,腾出一个空余位置

通过System的静态方法arraycopy()完成元素的拷贝,arraycopy()的第一个参数为源数组对象,第二个参数为源数组对象的起始下标(从哪个元素开始拷贝),第三个参数为目标数组对象,第四个参数为目标数组对象的起始下标(从哪个元素开始粘贴),第五个参数为需要拷贝的元素数量!此处只需挪出一个位置,即可存放即将要插入的元素!

5、向指定位置插入元素

已经腾出空余空间,只需将元素插入到数组的指定下标处即可

6、元素总数增加

Vector对象持有的elementCount增加1

addElement()方法分析

    public synchronized void addElement(E obj) {
        modCount++;
        ensureCapacityHelper(elementCount + 1);
        elementData[elementCount++] = obj;
    }

同样为synchronized修饰,添加一个元素的方法,有一点和add()方法不同,它没有返回值…………,几乎都一样,这里不再冗余分析

addAll()方法分析

    public synchronized boolean addAll(Collection<? extends E> c) {
        modCount++;
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityHelper(elementCount + numNew);
        System.arraycopy(a, 0, elementData, elementCount, numNew);
        elementCount += numNew;
        return numNew != 0;
    }

用于添加多个元素的方法,传入的参数为Collection对象,表示持有多个元素的集合对象,本身方法同样是由synchronized修饰

1、为modCount值增加1,表示Vecor对象持有的元素发生改变,fail-fast机制会用到该值

2、先将Collection对象,转换成一个Object[]数组对象,并由局部变量a负责保存

3、获取转换数组后的长度,由局部变量numNew负责保存

4、调用ensureCpacityHelper()方法,将需要的新容量(elementCount+numNew)传入进去,检查现有数组容量能否存储下新的元素数量

5、使用System的静态方法arraycopy(),复制新的元素到旧的数组中,完成添加元素行为

6、更新elementCount总数

7、返回添加结果,只要添加的数量不是0,说明添加元素成功

addAll(int,Collection)方法分析

    public synchronized boolean addAll(int index, Collection<? extends E> c) {
        modCount++;
        if (index < 0 || index > elementCount)
            throw new ArrayIndexOutOfBoundsException(index);
        Object[] a = c.toArray();
        int numNew = a.length;
        ensureCapacityHelper(elementCount + numNew);
        int numMoved = elementCount - index;
        if (numMoved > 0)
            System.arraycopy(elementData, index, elementData, index + numNew,
                             numMoved);
        System.arraycopy(a, 0, elementData, index, numNew);
        elementCount += numNew;
        return numNew != 0;
    }

在指定位置添加多个元素的方法,传入的参数index表示指定的下标、传入的参数c表示要添加元素集合对象,同样为synchronized修饰,只有获取到对象锁的线程才能执行该方法,java的线程间同步做的真的太好!

1、更新modCount值,用于fail-fast机制检测

2、检查下标范围是否合法,不合法抛出ArrayIndexOutOfBoundsException提示用户

3、Collection对象转数组对象

4、获取转换后数组对象的长度

5、确认是否需要扩容数组容量

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

7、确定需要移动元素,使用System的静态方法arraycopy()移动元素

8、将新插入的所有元素,都赋值到elementData数组中,就从指定下标index开始

9、更新元素总数值

10、返回添加结果,不为0,即为True

ListItr中的add()方法分析

        public void add(E e) {
            int i = cursor;
            synchronized (Vector.this) {
                checkForComodification();
                Vector.this.add(i, e);
                expectedModCount = modCount;
            }
            cursor = i + 1;
            lastRet = -1;
        }

迭代器对象,可以添加元素,必须可以

1、先将遍历到哪个元素的游标保存到局部变量i中

2、只有获取到对象锁的线程,才能执行该代码块,此处仍为当前Vector对象作为对象锁

检查fail-fast机制

使用Vector的add(int,E)方法进行添加元素

更新一个预期值,expetcedModCount,这个也是用于fail-fast机制检测用的

3、更新游标值,增加1

4、更新迭代器对象持有的lastRet值为-1,表示上一次并没有进行遍历元素的行为

总结

1、Vector使用了一手synchronized,这也是导致效率变低的原因

2、假设1个线程执行插入操作需要5s,而其它n个线程操作任意一个Vecotor的方法,因为没有持有当前的Vector对象锁,所有的n个线程都被阻塞了……,同一时刻,只有1个线程能操作Vector的1个方法

3、如果只是读的操作,完全没有必要线程间同步啊,毕竟读的内存值一直没变啊,所以后来大牛不建议使用Vector

以上就是基于java构造方法Vevtor添加元素源码分析的详细内容,更多关于java构造方法Vevtor的资料请关注我们其它相关文章!

(0)

相关推荐

  • java构造函数示例(构造方法)

    TestCar.java 复制代码 代码如下: public class TestCar {    public static void main(String[] args) {        Car c1 = new Car();        c1.color = "red";        c1.brand = "xxx";//如果这辆汽车有很多属性,这样一一赋值不是很麻烦?有没有办法一生产出来就设定它的属性(初始化)吗?有~~~看下面          

  • Java数组添加元素实例

    以下实例演示了如何使用sort()方法对Java数组进行排序,及如何使用 insertElement () 方法向数组插入元素, 这边我们定义了 printArray() 方法来打印数组: MainClass.java 文件: import java.util.Arrays; public class MainClass { public static void main(String args[]) throws Exception { int array[] = { 2, 5, -2, 6,

  • Java链表中添加元素的原理与实现方法详解

    本文实例讲述了Java链表中添加元素的原理与实现方法.分享给大家供大家参考,具体如下: 1.链表中头节点的引入 1.1基本的链表结构: 1.2对于链表来说,若想访问链表中每个节点则需要把链表的头存起来,假如链表的头节点为head,指向链表中第一个节点,如图: 1.3使用代码表示此时的链表 //定义头节点 private Node head; //节点个数 private int size; //无参数构造函数 public LinkedList() { head = null; size = 0

  • 基于java构造方法Vector创建对象源码分析

    目录 前言 构造方法Vector()分析 构造方法Vector(int)分析 构造方法Vecotor(int,int)分析 构造方法Vector(Collection)分析 重要字段介绍(不含基类中定义的字段) (注意:本文基于JDK1.8) 前言 Vector是线程安全的动态数组类,提供4个创建Vector对象的构造方法,接下来我们逐个分析每个创建Vector对象的构造方法 构造方法Vector()分析 public Vector() { this(10); } 用于创建Vector对象的默认

  • 基于java构造方法Vevtor添加元素源码分析

    目录 前言 add(E)方法分析 add(int,E)方法分析 insertElementAt()方法分析 addElement()方法分析 addAll()方法分析 addAll(int,Collection)方法分析 ListItr中的add()方法分析 总结 (注意:本文基于JDK1.8) 前言 算上迭代器的add()方法,Vector中一共有7个添加元素的方法,5个添加单个元素的方法,2个添加多个元素的方法,接下来就一起分析它们的实现--Vector是一个线程安全的容器类,它的添加功能是

  • Java编程中ArrayList源码分析

    之前看过一句话,说的特别好.有人问阅读源码有什么用?学习别人实现某个功能的设计思路,提高自己的编程水平. 是的,大家都实现一个功能,不同的人有不同的设计思路,有的人用一万行代码,有的人用五千行.有的人代码运行需要的几十秒,有的人只需要的几秒..下面进入正题了. 本文的主要内容: · 详细注释了ArrayList的实现,基于JDK 1.8 . ·迭代器SubList部分未详细解释,会放到其他源码解读里面.此处重点关注ArrayList本身实现. ·没有采用标准的注释,并适当调整了代码的缩进以方便介

  • JAVA 枚举单例模式及源码分析的实例详解

    JAVA 枚举单例模式及源码分析的实例详解 单例模式的实现有很多种,网上也分析了如今实现单利模式最好用枚举,好处不外乎三点: 1.线程安全 2.不会因为序列化而产生新实例 3.防止反射攻击但是貌似没有一篇文章解释ENUM单例如何实现了上述三点,请高手解释一下这三点: 关于第一点线程安全,从反编译后的类源码中可以看出也是通过类加载机制保证的,应该是这样吧(解决) 关于第二点序列化问题,有一篇文章说枚举类自己实现了readResolve()方法,所以抗序列化,这个方法是当前类自己实现的(解决) 关于

  • java 中RandomAccess接口源码分析

    java 中RandomAccess接口源码分析 RandomAccess是一个接口,位于java.util包中. 这个接口的作用注释写的很清楚了: /** * Marker interface used by <tt>List</tt> implementations to indicate that * they support fast (generally constant time) random access. The primary * purpose of this

  • Java线程变量ThreadLocal源码分析

    1.ThreadLocal 线程变量,和当前线程绑定的,只保存当前线程的变量,对于其他线程是隔离的,是访问不到里面的数据的. 2.在Looper中使用到了ThreadLocal,创建了一个Looper是保存到了ThreadLocal中. //这里用到了泛型,ThreadLocal中只保存Looper对象. static final ThreadLocal<Looper> sThreadLocal = new ThreadLocal<Looper>(); private static

  • java并发之AtomicInteger源码分析

    问题 (1)什么是原子操作? (2)原子操作和数据库的ACID有啥关系? (3)AtomicInteger是怎么实现原子操作的? (4)AtomicInteger是有什么缺点? 简介 AtomicInteger是java并发包下面提供的原子类,主要操作的是int类型的整型,通过调用底层Unsafe的CAS等方法实现原子操作. 还记得Unsafe吗?点击链接直达[java Unsafe详细解析] 原子操作 原子操作是指不会被线程调度机制打断的操作,这种操作一旦开始,就一直运行到结束,中间不会有任何

  • Java集合框架ArrayList源码分析(一)

    ArrayList底层维护的是一个动态数组,每个ArrayList实例都有一个容量.该容量是指用来存储列表元素的数组的大小.它总是至少等于列表的大小.随着向 ArrayList 中不断添加元素,其容量也自动增长. ArrayList不是同步的(也就是说不是线程安全的),如果多个线程同时访问一个ArrayList实例,而其中至少一个线程从结构上修改了列表,那么它必须保持外部同步,在多线程环境下,可以使用Collections.synchronizedList方法声明一个线程安全的ArrayList

  • Java StringBuilder和StringBuffer源码分析

    StringBuilder与StringBuffer是两个常用的操作字符串的类.大家都知道,StringBuilder是线程不安全的,而StringBuffer是线程安全的.前者是JDK1.5加入的,后者在JDK1.0就有了.下面分析一下它们的内部实现. 一.继承关系 public final class StringBuffer extends AbstractStringBuilder implements java.io.Serializable, CharSequence public

  • 基于java构造方法Vector查找元素源码分析

    目录 前言 get(int)方法分析 contains(Object)方法分析 containsAll()方法分析 indexOf(Object)方法分析 indexOf(Object,index)方法分析 lastIndexOf(Object)方法分析 elementAt(int)方法分析 firstElement()方法分析 lastElement()方法分析 elementData(int)方法分析 总结 (注意:本文基于JDK1.8) 前言 元素在存储到内存中,当我们需要使用在内存中存储

随机推荐