JDK source code parsing --ArrayList

JDK source code parsing --ArrayList

In this paper, JDK1.8

Outline

ArrayList, based []arrays, support for automatic expansion dynamic array. Compared array, because it supports automatic expansion characteristics become our daily development, the most commonly used collections, not one.

Class Diagram

1584625237213

Attributes

    private static final long serialVersionUID = 8683452581122892189L;

    /**
     * Default initial capacity.默认容量是10
     */
    private static final int DEFAULT_CAPACITY = 10;

    /**
     * Shared empty array instance used for empty instances.
     */
    private static final Object[] EMPTY_ELEMENTDATA = {};

    /**
     * Shared empty array instance used for default sized empty instances. We
     * distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
     * first element is added.
     */
    private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

    /**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

    /**
     * The size of the ArrayList (the number of elements it contains).
     *
     * @serial
     */
    private int size;

1584625496439

  • elementDataAttribute: element of the array. Among them, the red box represents the figure we have added elements, we did not use white space behalf.
  • sizeProperties: array size. Note that sizerepresents ArrayList used elementDatathe number of elements, developers can see for #size()also the size. And when we add new elements, which is exactly the element to elementDatathe position (subscript). Of course, we know that ArrayList real size is the elementDatasize.

Construction method

There are three ArrayList constructor, we were to look at.

#ArrayList(int initialCapacity)

#ArrayList(int initialCapacity)Construction method, based on the passed initial capacity, create ArrayList array. If we use, if the pre-assigned to the array size, be sure to use the constructor to avoid expansion of the array to enhance performance, but also the rational use of memory. code show as below:

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}
  • If the initial capacity is 0, use of EMPTY_ELEMENTDATAan empty array. When adding elements to create an array of expansion it will be needed. It will introduce the expansion mechanism below.

#ArrayList(Collection<? extends E> c)

#ArrayList(Collection<? extends E> c)Construction method using the incoming cset as the ArrayList elementData. code show as below:

public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        //JDK8存在BUG,它在 JDK9 中被解决,。
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}

#ArrayList()

No-argument constructor #ArrayList()constructor, but also our most used constructor. code show as below:

public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

Q: public ArrayList(0)and public ArrayList()two constructors What is the difference?

Before answering this question, we look at ArrayListthe two member variables:

These are two empty Object array, but need to note that this is an array of objects == == two.

private static final Object[] EMPTY_ELEMENTDATA = {};
    
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};

We can see, public ArrayList(0)will elementDataarray assignment asEMPTY_ELEMENTDATA

public ArrayList()Will elementDataarray assignment is DEFAULTCAPACITY_EMPTY_ELEMENTDATA, though they are empty array, but this is two objects!

public ArrayList(int initialCapacity) {
    if (initialCapacity > 0) {
        this.elementData = new Object[initialCapacity];
    } else if (initialCapacity == 0) {
        this.elementData = EMPTY_ELEMENTDATA;
    } else {
        throw new IllegalArgumentException("Illegal Capacity: "+
                                           initialCapacity);
    }
}
public ArrayList() {
    this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}

In the following, we will see the DEFAULTCAPACITY_EMPTY_ELEMENTDATAfirst expansion to 10 , and EMPTY_ELEMENTDATAin accordance with 1.5 times the expansion starts at 0 instead of 10. Two different starting points.

Add a single element

#add(E e)The method, the order to add a single element to the array, the method returns a boolean variable. code show as below:

public boolean add(E e) {
    ensureCapacityInternal(size + 1);  // Increments modCount!!
    elementData[size++] = e;
    return true;
}

#add(int index, E element)Method, the sequence is inserted into a single element array. Provided that the index > size || index < 0code is as follows:

public void add(int index, E element) {
        rangeCheckForAdd(index);//先检查index是否合法

        ensureCapacityInternal(size + 1);  // Increments modCount!!
         // 将 index + 1 位置开始的元素,进行往后挪
        System.arraycopy(elementData, index, elementData, index + 1,
                         size - index);
        elementData[index] = element;
        size++;
    }
  • It is worth noting here the #ensureCapacityInternal(int minCapacity)method. Its role is to ensure that elementDatathe array has a capacity of at least minCapacity, minCapacityis at least 1
private void ensureCapacityInternal(int minCapacity) {
    if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
  //如果是DEFAULTCAPACITY_EMPTY_ELEMENTDATA对象,则将minCapacity设为DEFAULT_CAPACITY(10)
        minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
    }

    ensureExplicitCapacity(minCapacity);
}

Which #ensureExplicitCapacity(int minCapacity)method

private void ensureExplicitCapacity(int minCapacity) {
    modCount++;

    // overflow-conscious code
    if (minCapacity - elementData.length > 0)//如果minCapacity超出elementData数组长度,则扩容
        grow(minCapacity);
}

Array Expansion

#grow()Method, the array expansion and return it. The entire expansion process, first create a new, larger array, typically 1.5 times the size (Why is it generally does, we will see later, there will be some small details), and then copy the original array to a new array Finally, return to the new array. code show as below:

 private void grow(int minCapacity) {
     // overflow-conscious code
     int oldCapacity = elementData.length;
     int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍扩容
     if (newCapacity - minCapacity < 0)
         //此时有一种情况:如果elementData为空,newCapacity仍为0,newCapacity置为1
         newCapacity = minCapacity;
     if (newCapacity - MAX_ARRAY_SIZE > 0)
         newCapacity = hugeCapacity(minCapacity);
     // minCapacity is usually close to size, so this is a win:
     elementData = Arrays.copyOf(elementData, newCapacity);
 }

Among them, #hugeCapacity(int minCapacity)as follows:


private static int hugeCapacity(int minCapacity) {
    if (minCapacity < 0) // overflow
        throw new OutOfMemoryError();
    return (minCapacity > MAX_ARRAY_SIZE) ?
        Integer.MAX_VALUE :
    MAX_ARRAY_SIZE;
}

Q: ArrayList maximum capacity problem?

rivate static final int MAX_ARRAY_SIZE = Integer.MAX_VALUE - 8;

The maximum capacity of Integer.MAX_VALUE-8,

public ArrayList(int initialCapacity)

By the above configuration specified initial capacity function, and the maximum value is int Integer.MAX_VALUE, -8 to avoid OOM, vm may be stored as some header information in the array. Thus a maximum capacity Integer.MAX_VALUE-8. But when MAX_ARRAY_SIZE still not enough, the capacity will be extended to HugeCapacity, as Integer.MAX_VALUE.

private void grow(int minCapacity) {//保证 elementData 数组容量至少有 minCapacity
        // overflow-conscious code
        int oldCapacity = elementData.length;
        int newCapacity = oldCapacity + (oldCapacity >> 1);//1.5倍扩容
        if (newCapacity - minCapacity < 0)//若扩容之后,新容量还不够,就将新容量设为minCapacity
            newCapacity = minCapacity;
        if (newCapacity - MAX_ARRAY_SIZE > 0)
            newCapacity = hugeCapacity(minCapacity);
        // minCapacity is usually close to size, so this is a win:
        elementData = Arrays.copyOf(elementData, newCapacity);
}

An array of volume reduction

#trimToSize()The length of the array elementData clipped to the size of the current size. code show as below:

public void trimToSize() {
        modCount++;
        if (size < elementData.length) {
            elementData = (size == 0)
              ? EMPTY_ELEMENTDATA//如果elementData已空,则将EMPTY_ELEMENTDATA赋值过去
              : Arrays.copyOf(elementData, size);
        }
    }
  • And this point HashMapis different HashMapUnavailable volume reduction method.

Adding more elements

#addAll(Collection<? extends E> c)Methods, batch add more elements. When we clearly know will add more elements, the method recommended that instead of adding individual elements to avoid possible multiple expansion. code show as below:

//向elementData数组末尾添加元素
public boolean addAll(Collection<? extends E> c) {
    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount,保证 elementData 数组容量够用
    System.arraycopy(a, 0, elementData, size, numNew);//直接在elementData数组末尾添加元素
    size += numNew;
    return numNew != 0;//若添加的Collection为空,则返回false
}

#addAll(int index, Collection<? extends E> c)The method, from the initial insertion position of the specified plurality of elements, provided that index > size || index < 0. code show as below:

//向elementData数组中间(index处)插入元素
public boolean addAll(int index, Collection<? extends E> c) {
    rangeCheckForAdd(index);//先检查index是否合法

    Object[] a = c.toArray();
    int numNew = a.length;
    ensureCapacityInternal(size + numNew);  // Increments modCount,保证 elementData 数组容量够用
    int numMoved = size - index;
    if (numMoved > 0)
        //elementData数组中间(index处)插入元素
        //例如elementData数组原来为{"a","b","c","d"},需要在index=1处添加数据{"q","w"}
        //插入之后,elementData数组变为{"a","q","w","b","c","d"}
        System.arraycopy(elementData, index, elementData, index + numNew,
                         numMoved);//elementData数组index及以后元素往后移位index + numNew

    System.arraycopy(a, 0, elementData, index, numNew);//将a数组填入
    size += numNew;
    return numNew != 0;
}

Remove individual elements

#remove(int index)The method of removing the element specified position, and returns to the original position of the element. code show as below:

public E remove(int index) {
    rangeCheck(index);//先检查index是否合法,index >= size则抛异常

    modCount++;
    E oldValue = elementData(index);

    int numMoved = size - index - 1;
    if (numMoved > 0)
        System.arraycopy(elementData, index+1, elementData, index,
                         numMoved);
    elementData[--size] = null; // clear to let GC do its work

    return oldValue;
}

#remove(Object o)The method removes the first element in the array appears. code show as below:

public boolean remove(Object o) {
        if (o == null) {
            for (int index = 0; index < size; index++)
                if (elementData[index] == null) {
                    fastRemove(index);
                    return true;
                }
        } else {
            for (int index = 0; index < size; index++)
                if (o.equals(elementData[index])) {
                    fastRemove(index);
                    return true;
                }
        }
        return false;
    }
  • among them,#fastRemove(int index)
 private void fastRemove(int index) {
     modCount++;
     int numMoved = size - index - 1;
     if (numMoved > 0)
         System.arraycopy(elementData, index+1, elementData, index,
                          numMoved);
     elementData[--size] = null; // clear to let GC do its work
 }

Remove multiple elements

#removeAll(Collection<?> c), The bulk removal of elementDataspecified multiple elements.

public boolean removeAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, false);
}

#retainAll(Collection<?> c)To retain elementDatamore of the elements specified, delete all the rest.

public boolean retainAll(Collection<?> c) {
    Objects.requireNonNull(c);
    return batchRemove(c, true);
}
  • Both methods are used #batchRemove(Collection<?> c, boolean complement)to achieve, 他们的区别就是boolean complementwhether true.
private boolean batchRemove(Collection<?> c, boolean complement) {
    final Object[] elementData = this.elementData;
    int r = 0, w = 0;
    boolean modified = false;
    try {
        for (; r < size; r++)
            if (c.contains(elementData[r]) == complement)// 判断符合条件
                // 移除的方式,通过将当前值 写入到 w 位置,然后 w 跳到下一个位置。
                elementData[w++] = elementData[r];
    } finally {
        // Preserve behavioral compatibility with AbstractCollection,
        // even if c.contains() throws.
        if (r != size) {
            //如果 contains 方法发生异常,则将 elementData的元素从 r 位置的数据写入到 es 从 w 开始的位置
            System.arraycopy(elementData, r,
                             elementData, w,
                             size - r);
            w += size - r;
        }
        if (w != size) {
            // clear to let GC do its work
            for (int i = w; i < size; i++)
                elementData[i] = null;
            modCount += size - w;
            size = w;
            modified = true;
        }
    }
    return modified;
}
  • If you think about, and more debugging, you can hand-drawn at the point chart, assist understanding Kazakhstan.

Find a single element

#indexOf(Object o)Method, find the first position to the specified element, if not found, it returns - 1. code show as below:

public int indexOf(Object o) {
    //分为o为null和不为null两种情况
    if (o == null) {
        for (int i = 0; i < size; i++)
            if (elementData[i]==null)
                return i;
    } else {
        for (int i = 0; i < size; i++)
            if (o.equals(elementData[i]))
                return i;
    }
    return -1;
}

The #contains(Object o)method is based on the methods. code show as below:

public boolean contains(Object o) {
    return indexOf(o) >= 0;
}

Obtain the specified location element

#get(int index)Methods, access element at the location. code show as below:

public E get(int index) {
        rangeCheck(index);//先检查index是否合法,index >= size则抛异常

        return elementData(index);
    }

Setting element at the location

#set(int index, E element)A method, set the element specified position, return the old value. code show as below:

public E set(int index, E element) {
    rangeCheck(index);//先检查index是否合法,index >= size则抛异常

    E oldValue = elementData(index);
    elementData[index] = element;
    return oldValue;
}

Into an array

#toArray()A method to convert into ArrayList []array. code show as below:

// ArrayList.java

public Object[] toArray() {
    return Arrays.copyOf(elementData, size);
}

// Arrays.java

public static <T> T[] copyOf(T[] original, int newLength) {
    return (T[]) copyOf(original, newLength, original.getClass());
}
  • Note that the return of a Object[]type.

Under the actual scenario, we may want to specify Ta generic array, then we need to use the #toArray(T[] a)method. code show as below:

 public <T> T[] toArray(T[] a) {
     if (a.length < size)//如果传入的数组小于 size 大小,则直接复制一个新数组返回
         // Make a new array of a's runtime type, but my contents:
         return (T[]) Arrays.copyOf(elementData, size, a.getClass());
     //将 elementData 复制到 a 中
     System.arraycopy(elementData, 0, a, 0, size);
     //如果传入的数组大于 size 大小,则将 size 赋值为 null
     if (a.length > size)
         a[size] = null;
     return a;
 }
  • So there are two ways to get the specified Tarray of generic :( Suppose we want to list into an array of type String)
    • list.toArray(new Sring[0]); Returns a new array
    • list.toArray(new Sring[list.size()]); It is a return array, the performance slightly higher -

Create a sub-array

#subList(int fromIndex, int toIndex)Method, create a sub-array ArrayList, the attention does not contain toIndexOh. code show as below:

public List<E> subList(int fromIndex, int toIndex) {
    subListRangeCheck(fromIndex, toIndex, size);//检查参数是否合法
    return new SubList(this, 0, fromIndex, toIndex);
}

private static class SubList<E> extends AbstractList<E> implements RandomAccess {

    /**
     * 根 ArrayList
     */
    private final ArrayList<E> root;
    /**
     *  父 SubList
     */
    private final SubList<E> parent;
    /**
     * 起始位置
     */
    private final int offset;
    /**
     * 大小
     */
    private int size;

    // ... 省略代码
}
  • Actual use, must pay attention to, SubList not a read-only array, but an array of roots and rootshare the same elementDataarray, but said limiting the [fromIndex, toIndex)scope.

System.arraycopy() :

public static void arraycopy(
                             Object src,  //源数组
                             int srcPos,  //源数组的起始位置
                             Object dest, //目标数组
                             int destPos, //目标数组的起始位置
                             int length   //复制长度
                             )

Reference to the following: https: //segmentfault.com/a/1190000009922279

Deep or shallow copy copy

Code: Copy array of objects:

public class SystemArrayCopyTestCase {

    public static void main(String[] args) {
        User[] users = new User[] { 
                new User(1, "seven", "[email protected]"), 
                new User(2, "six", "[email protected]"),
                new User(3, "ben", "[email protected]") };// 初始化对象数组
        
        User[] target = new User[users.length];// 新建一个目标对象数组
        
        System.arraycopy(users, 0, target, 0, users.length);// 实现复制
        
        System.out.println("源对象与目标对象的物理地址是否一样:" + (users[0] == target[0] ? "浅复制" : "深复制"));  //浅复制
        
        target[0].setEmail("[email protected]");
        
        System.out.println("修改目标对象的属性值后源对象users:");
        for (User user : users) {
            System.out.println(user);
        }
        //
        //
        //
    }
}

class User {
    private Integer id;
    private String username;
    private String email;

    // 无参构造函数
    public User() {
    }

    // 有参的构造函数
    public User(Integer id, String username, String email) {
        super();
        this.id = id;
        this.username = username;
        this.email = email;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getEmail() {
        return email;
    }

    public void setEmail(String email) {
        this.email = email;
    }

    @Override
    public String toString() {
        return "User [id=" + id + ", username=" + username + ", email=" + email + "]";
    }
}

Illustrates: object copy illustration

clipboard.png

Therefore, it was concluded that, System.arraycopy()in a copy of the array when using shallow copy, copy the result is a reference to the use of one-dimensional pass variables to a copy of the one-dimensional array, modifying the copy, it will affect the original array.


The difference copy of one-dimensional arrays and multidimensional arrays

Code: Copy a one-dimensional array

        String[] st  = {"A","B","C","D","E"};
        String[] dt  = new String[5];
        System.arraycopy(st, 0, dt, 0, 5);
        
        //改变dt的值
        dt[3] = "M";
        dt[4] = "V";
        
        System.out.println("两个数组地址是否相同:" + (st == dt)); //false
        
        for(String str : st){
            System.out.print(" " + str +" ");   // A  B  C  D  E 
            
        }
        System.out.println(); 
        for(String str : dt){
            System.out.print(" " + str +" ");   // A  B  C  M  V 
        }

After using this method during reproduction of one-dimensional array, the target does not affect the original data array to be modified, the value of this attribute copy pass, modify the copy does not affect the original value.

However, please look at the focus of the following codes:

        String[] st  = {"A","B","C","D","E"};
        String[] dt  = new String[5];
        System.arraycopy(st, 0, dt, 0, 5);

       for(String str : st){
            System.out.print(" " + str +" ");   // A  B  C  D  E 
            
        }
        System.out.println(); 
        for(String str : dt){
            System.out.print(" " + str +" ");   // A  B  C  D  E 
        }

        System.out.println("数组内对应位置的String地址是否相同:" + st[0] == dt[0]); // true

Since it is the attribute value passed, and why st[0] == dt[0]? Do we go any further would be equal to test:

        String[] st  = {"A","B","C","D","E"};
        String[] dt  = new String[5];
        System.arraycopy(st, 0, dt, 0, 5);
        dt[0] = "F" ;
        
        for(String str : st){
            System.out.print(" " + str +" ");   // A  B  C  D  E 
            
        }
        System.out.println(); 
        for(String str : dt){
            System.out.print(" " + str +" ");   // F  B  C  D  E 
        }


        System.out.println("数组内对应位置的String地址是否相同:" + st[0] == dt[0]); // false

Why the above situation will happen?

Can be inferred by the above two pieces of code, at System.arraycopy()the time of the copy, the first check whether the literal string constant pool amount, when present, the process directly returns the corresponding memory address, such as absence of the open space in the memory storage corresponding to Object.

Code: Copy a two-dimensional array

        String[][] s1 = {
                    {"A1","B1","C1","D1","E1"},
                    {"A2","B2","C2","D2","E2"},
                    {"A3","B3","C3","D3","E3"}
                        };
        String[][] s2 = new String[s1.length][s1[0].length];  
        
        System.arraycopy(s1, 0, s2, 0, s2.length);  
        
        for(int i = 0;i < s1.length ;i++){ 
         
           for(int j = 0; j< s1[0].length ;j++){  
              System.out.print(" " + s1[i][j] + " ");
           }  
           System.out.println();  
        }  
        
        //  A1  B1  C1  D1  E1 
        //  A2  B2  C2  D2  E2 
        //  A3  B3  C3  D3  E3 
        
        
        s2[0][0] = "V";
        s2[0][1] = "X";
        s2[0][2] = "Y";
        s2[0][3] = "Z";
        s2[0][4] = "U";
        
        System.out.println("----修改值后----");  
        
        
        for(int i = 0;i < s1.length ;i++){  
               for(int j = 0; j< s1[0].length ;j++){  
                  System.out.print(" " + s1[i][j] + " ");
               }  
               System.out.println();  
         }  

        //  Z   Y   X   Z   U 
        //  A2  B2  C2  D2  E2 
        //  A3  B3  C3  D3  E3 

It said code is a two-dimensional array of replication, a first dimension of the array is mounted a one-dimensional array of reference, is the second virial element values. After a two-dimensional array to copy, the first dimension of the first dimension references are copied to the new array, which is the first two-dimensional arrays point to the same "as those arrays." And then change the value of any element of an array which, in fact modify the value of the element "Those arrays", so the element value of the original and the new array are the same.


Thread-safe, or unsafe

Code: Multithreading copy of the array (java in System.arraycopya thread-safe?)

public class ArrayCopyThreadSafe {
    private static int[] arrayOriginal = new int[1024 * 1024 * 10];
    private static int[] arraySrc = new int[1024 * 1024 * 10];
    private static int[] arrayDist = new int[1024 * 1024 * 10];
    private static ReentrantLock lock = new ReentrantLock();

    private static void modify() {
        for (int i = 0; i < arraySrc.length; i++) {
            arraySrc[i] = i + 1;
        }
    }

    private static void copy() {
        System.arraycopy(arraySrc, 0, arrayDist, 0, arraySrc.length);
    }

    private static void init() {
        for (int i = 0; i < arraySrc.length; i++) {
            arrayOriginal[i] = i;
            arraySrc[i] = i;
            arrayDist[i] = 0;
        }
    }

    private static void doThreadSafeCheck() throws Exception {
        for (int i = 0; i < 100; i++) {
            System.out.println("run count: " + (i + 1));
            init();
            Condition condition = lock.newCondition();

            new Thread(new Runnable() {
                @Override
                public void run() {
                    lock.lock();
                    condition.signalAll();
                    lock.unlock();
                    copy();
                }
            }).start();


            lock.lock();
            // 这里使用 Condition 来保证拷贝线程先已经运行了.
            condition.await();
            lock.unlock();

            Thread.sleep(2); // 休眠2毫秒, 确保拷贝操作已经执行了, 才执行修改操作.
            modify();

            if (!Arrays.equals(arrayOriginal, arrayDist)) {
                throw new RuntimeException("System.arraycopy is not thread safe");
            }
        }
    }

    public static void main(String[] args) throws Exception {
        doThreadSafeCheck();
    }
}

Specific operation of this example is:

  1. When arrayOriginal and arraySrc initialization are the same, but arrayDist is all zeros.
  2. Start a thread running copy () method to copy the arraySrc to arrayDist.
  3. In the main thread execution modify () operation, modify the contents of arraySrc In order to ensure that the copy () operation prior to modify () operation, I use the Condition, and two millisecond delay, in order to ensure the implementation of the copy operation (ie System.arraycopy ) before the modification operation.
  4. According to the third point, if System.arraycopy is thread-safe, it runs the copy operation, when then modify operation will not affect the replication results, so arrayOriginal must equal arrayDist; and if System.arraycopy is thread-safe, so arrayOriginal not equal arrayDist.

Based on the above reasoning, run the program, the following output:

run count: 1
run count: 2
Exception in thread "main" java.lang.RuntimeException: System.arraycopy is not thread safe
    at com.test.ArrayCopyThreadSafe.doThreadSafeCheck(ArrayCopyThreadSafe.java:62)
    at com.test.ArrayCopyThreadSafe.main(ArrayCopyThreadSafe.java:68)

So, System.arraycopyit is unsafe.


Efficient or inefficient

Code: for vs System.arraycopyCopy array

        String[] srcArray = new String[1000000];
        String[] forArray = new String[srcArray.length];
        String[] arrayCopyArray  = new String[srcArray.length];
        
        //初始化数组
        for(int index  = 0 ; index  < srcArray.length ; index ++){
            srcArray[index] = String.valueOf(index);
        }
        
        long forStartTime = System.currentTimeMillis();
        for(int index  = 0 ; index  < srcArray.length ; index ++){
            forArray[index] = srcArray[index];
        }
        long forEndTime = System.currentTimeMillis();
        System.out.println("for方式复制数组:"  + (forEndTime - forStartTime));

        long arrayCopyStartTime = System.currentTimeMillis();
        System.arraycopy(srcArray,0,arrayCopyArray,0,srcArray.length);
        long arrayCopyEndTime = System.currentTimeMillis();
        System.out.println("System.arraycopy复制数组:"  + (arrayCopyEndTime - arrayCopyStartTime));

Through the above code, when the scope of the test array of relatively small, a difference of a little time, when the length of the test array reach one million level, System.arraycopy speed advantage began to reflect, according to the understanding of the underlying, System. arraycopy direct memory copy is reduced addressing time for the cycle, thereby improving performance.

to sum up

  • ArrayList is based []List implementation class implemented array, the array support when capacity is insufficient, in accordance with generally 1.5 times the automatic expansion. At the same time, it supports the manual expansion, manual volume reduction.

  • Source involving migration to replicate many of the array,System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length);

This method belongs to the shallow copy, thread-safe, it reduces the time for addressing cycle, compared to the forcycle for improved performance.

If you do not have a place to spike the text, please criticism.

the above.

Guess you like

Origin www.cnblogs.com/yifengGG/p/12531200.html