zoukankan      html  css  js  c++  java
  • 作业12:List集合类

    一 为什么使用List?

    1 List与数组

    List 数组
    可变长度 固定长度
    方便的接口(支持Java8的Stream) /

    2 List的实现方式

    • 数组:ArrayList

      • 查询效率比较高
      • 插入效率比较低(指的是add(int index, E element)方法,不是add(E element)方法。)
      • 特殊情况下,数量多时,空间占用比LinkedList高(当数组刚刚扩容1.5,约等于3分之1的空间没有利用。)
    • 链表:LinkedList

      • 查询效率比较低
      • 插入效率比较高
      • 数量少时,空间占用比ArrayList高
    • 空间占用计算

    默认开启指针压缩:对象头占用12字节,8字节填充格式
    
    new Integer(1) = 12 bytes 对象头 + 4 bytes int value = 16 bytes
    new Integer[1] = 12 bytes 对象头 + 4 bytes 数组指针 + 4 bytes int value + 4 bytes 填充 = 24 bytes
    
    验证数量少时,LinkedList的空间占用高(以单向链表计算)
    (1)单个Node占用 = 12 bytes 对象头 + 4 bytes next 指针 +16 bytes 元素占用(以Integer为例子)= 32 bytes
    new MyLinkedList() 并 添加N个元素 = N * 32 bytes Node 占用 +( 2*4 bytes first 和 last 指针占用 + 4 bytes size 字段占用(int)+ 12 bytes 对象头 ) =  32N+24 bytes
    
    (2)new MyArrayList() 并 添加N个元素 = (12 bytes 对象头 + 4 bytes 数组指针占用 + 4*N + 填充字节?) + (4 bytes 数组指针占用 + 4 bytes size字段占用 + 12 bytes 对象头 + 4 bytes 填充 )= 20 + 4N + 填充字节? + 24 bytes
    
    但是数组可能存在3分之1的浪费,所以随着N的增长,总有个时刻,ArrayList的占用比LinkedList高。
    

    对象占用空间大小参考:https://blog.csdn.net/u013256816/article/details/51008443

    3 自己实现一个可变数组

    (1)数组方式

    import java.util.Iterator;
    
    /**
     * 因为jdk的List接口太多方法了,所以没实现。
     * @param <E>
     */
    public class MyArrayList<E> {
        private int size;
        private Object[] objs;
    
        public MyArrayList() {
            // 从零开始:因为可能创建对象之后一直不添加元素。
            this(0);
        }
    
        public MyArrayList(int size) {
            this.objs = new Object[size];
            this.size = size;
        }
    
        private void resize(int capacity) {
            if (capacity == 0) capacity = 1;
            Object[] copy = new Object[capacity];
            for (int i = 0; i < size; i++)
                copy[i] = objs[i];
            objs = copy;
        }
    
        public int size() {
            return size;
        }
    
        public boolean isEmpty() {
            return size == 0;
        }
    
        public Iterator<E> iterator() {
            return new ArrayIterator<>();
        }
    
        public void add(E e) {
            // 扩容方式:翻倍
            if (size == objs.length) resize(2 * objs.length);
            objs[size++] = e;
        }
    
        private void checkArgument(int index) {
            if (index < 0 || index >= size)
                throw new IndexOutOfBoundsException();
        }
    
        public E get(int index) {
            checkArgument(index);
            return (E) objs[index];
        }
    
        private void shift(int index) {
            for (int i = index; i < size - 1; i++)
                objs[i] = objs[i + 1];
            objs[--size] = null;
        }
    
        public E remove(int index) {
            checkArgument(index);
            E obj = (E) objs[index];
            shift(index);
            // 扩容方式:减半
            if (size > 0 && size == objs.length / 4)
                resize(objs.length / 2);
            return obj;
        }
    
        @Override
        public String toString() {
            StringBuilder str = new StringBuilder("[");
            for (int i = 0; i < size; i++) {
                str.append(objs[i].toString());
                if (i != size - 1)
                    str.append(",");
            }
            return  str.append("]").toString();
        }
    
        private class ArrayIterator<E> implements Iterator<E> {
            private int next = 0;
    
            @Override
            public boolean hasNext() {
                return next < size;
            }
    
            @Override
            public E next() {
                if (!hasNext())
                    throw new RuntimeException("List hasn't next element.");
                return (E) objs[next++];
            }
        }
    
        // 测试方法
        public static void main(String[] args) {
            MyArrayList<String> list = new MyArrayList<>();
            list.add("My");
            list.add("Hello");
            list.add("World");
            System.out.println(list);
            Iterator<String> iterator = list.iterator();
            while (iterator.hasNext()) {
                String next = iterator.next();
                System.out.println(next);
            }
        }
    }
    

    (2)链表方式

    public class MyLinkedList<E> {
        private Node first;
        private Node last;
        private int size;
    
        public MyLinkedList() {
            first = null;
            last = null;
            size = 0;
        }
    
        // 单向链表
        private class Node {
            public Object t;
            public Node next;
    
            Node(Object t) {
                this.t = t;
            }
        }
    
        public int size() {
            return size;
        }
    
        public boolean isEmpty() {
            return size == 0;
        }
    
        public Iterator<E> iterator() {
            return new LinkedListIteraotr();
        }
    
        private class LinkedListIteraotr implements Iterator {
            private Node current = MyLinkedList.this.first;
    
            @Override
            public boolean hasNext() {
                return current != null;
            }
    
            @Override
            public E next() {
                if (!hasNext()) throw new NoSuchElementException();
                E t = (E) current.t;
                current = current.next;
                return t;
            }
        }
    
        public void add(E e) {
            Node node = new Node(e);
            if (isEmpty()) first = node;
            else last.next = node;
            last = node;
            size++;
        }
    
        private void checkArgument(int index) {
            if (index < 0 || index >= size)
                throw new IndexOutOfBoundsException();
        }
    
        public E get(int index) {
            checkArgument(index);
            return (E) findNode(index).t;
        }
    
        private Node findNode(int index) {
            Node node = first;
            for (int i = index; i > 0; i--)
                node = node.next;
            return node;
        }
    
        public E remove(int index) {
            checkArgument(index);
            E e ;
            if (size == 1) {
                Node node = findNode(index);
                e = (E) node.t;
                first = last = null;
            } else {
                if (index == 0) {
                    Node node = findNode(index);
                    e = (E) node.t;
                    first = node.next;
                } else if (index == size - 1) {
                    Node preNode = findNode(index - 1);
                    last = preNode;
                    e = (E) preNode.next.t;
                    preNode.next = null;
                } else {
                    Node preNode = findNode(index - 1);
                    Node midNode = preNode.next;
                    e = (E) midNode.t;
                    preNode.next = midNode.next;
                }
            }
            size--;
            return e;
        }
    
        @Override
        public String toString() {
            StringBuilder str = new StringBuilder("[");
            for (Node node = first; node != null; node = node.next) {
                str.append(node.t.toString());
                if (node.next != null)
                    str.append(",");
            }
            return str.append("]").toString();
        }
    
        public static void main(String[] args) {
            MyLinkedList<Integer> list = new MyLinkedList<>();
            list.add(1);
            list.add(2);
            list.add(3);
    //        list.remove(0);
    //        list.remove(1);
            System.out.println(list);
            Iterator<Integer> iterator = list.iterator();
            while (iterator.hasNext()){
                System.out.println(iterator.next());
            }
        }
    
    }
    

    温馨提示:Coursera 有基础算法课程,不是计算机专业,可以通过这个网站学习一下。

    4 JDK与自己实现比对

    (1)数组:ArrayList

    • 扩容:jdk为1.5倍,自己实现为2倍
    • 自己实现省略了异常和检测,如:容量不能超过Integer.MAX_VALUE
    • 省略了fail-fast(其他方案:fail-safe,简单来说就是复制一份数据进行遍历,这样多线程修改也不会发生异常,但是牺牲了实时性,空间开销较大。)异常检测机制
      • 定义:java集合类的一种错误机制,看源码可知多线程状态下去删除集合中的元素,将导致ConcurrentModificationException.
      • 实现:迭代前记住修改次数(modCount),其他线程进行修改时,modCount改变,与原来的不相符,所以直接抛出异常。
      • 注意:modCount没有用volatile修饰,意味着当一个线程修改了modCount,其他的线程并不能马上感知,即不保证fail-fast机制一定会发生
      • 猜想:至于jdk为什么不采用volatile修饰,我个人认为ArrayList既然不是线程安全的类,那么就不要在多线程中使用,这样就不会发生错误。多线程相关的操作:可见性也好,原子性也好,或多或少都会影响操作性能,所以jdk没有将modCount修饰为volatile吧。

    volatile的可见性参考:https://www.cnblogs.com/zhengbin/p/5654805.html

    • 其他API没实现,不做比较
    public class ArrayList<E> extends AbstractList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable{   
       
        transient Object[] elementData;
        
        // 1.扩容和异常检测
        //调用关系:add(E) -> add(E,Object[],int) -> grow -> grow(int) -> newCapacity(int)
        public boolean add(E e) {
            modCount++;// fail-fast机制,定义在AbstractList中
            add(e, elementData, size);
            return true;
        }
        
        private int newCapacity(int minCapacity) {
            int oldCapacity = elementData.length;
            // 扩容具体:1.5倍
            // 其他就是越界检测
            int newCapacity = oldCapacity + (oldCapacity >> 1);
            if (newCapacity - minCapacity <= 0) {
                if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA)
                    return Math.max(DEFAULT_CAPACITY, minCapacity);
                if (minCapacity < 0) throw new OutOfMemoryError();
                return minCapacity;
            }
            return (newCapacity-MAX_ARRAY_SIZE<=0)? newCapacity: hugeCapacity(minCapacity);
        }
        
        // 3.fail-fast
        // ArrayList非线程安全,不在多线程情况下使用,所以没有实现fail-fast机制。
        private class Itr implements Iterator<E> {
            // 省略了一部分方法
            int cursor;       // index of next element to return
            int lastRet = -1; // index of last element returned; -1 if no such
            int expectedModCount = modCount;
    
            // prevent creating a synthetic constructor
            Itr() {}
    
            public boolean hasNext() {
                return cursor != size;
            }
    
            @SuppressWarnings("unchecked")
            public E next() {
                // 具体看这个方法就好
                checkForComodification();
                int i = cursor;
                if (i >= size) throw new NoSuchElementException();
                Object[] elementData = ArrayList.this.elementData;
                if (i >= elementData.length) throw new ConcurrentModificationException();
                cursor = i + 1;
                return (E) elementData[lastRet = i];
            }
    		
            // 调用List.remove不修改expectedModCount,即单线程下需要在Iterator.remove删除元素。
            public void remove() {
                if (lastRet < 0) throw new IllegalStateException();
                checkForComodification();
    
                try {
                    ArrayList.this.remove(lastRet);
                    cursor = lastRet;
                    lastRet = -1;
                    expectedModCount = modCount;
                } catch (IndexOutOfBoundsException ex) {
                    throw new ConcurrentModificationException();
                }
            }
    
            // 很简单的方法:比对List的当前modCount和原先modCount
            final void checkForComodification() {
                if (modCount != expectedModCount)
                    throw new ConcurrentModificationException();
            }
        }
        
    }
    

    (2)链表:LinkedList

    • JDK实现了Deque接口(双向队列),所以内部的Node多了prev节点,即双向链表,我内部使用单向链表
    • 与ArrayList相同都有fail-fast机制,其他差不多,不贴代码了。
    public class LinkedList<E> extends AbstractSequentialList<E> implements List<E>, Deque<E>, Cloneable, java.io.Serializable{
        
    	private static class Node<E> {
            E item;
            Node<E> next;
            Node<E> prev;
    
            Node(Node<E> prev, E element, Node<E> next) {
                this.item = element;
                this.next = next;
                this.prev = prev;
            }
        }
    }
    

    5 增强For循环的实现原理

    (1)Java代码

    List<Integer> list = new ArrayList<>();
    list.add(new Integer(1));
    for (Object i : list){ }
    for (Integer i : list){ } // 类型检查并转换 Object -> Integer
    

    (2)字节码

    0: new           #2                  // class java/util/ArrayList
    3: dup
    4: invokespecial #3                  // Method java/util/ArrayList."<init>":()V
    7: astore_1
    8: aload_1
    9: new           #4                  // class java/lang/Integer
    12: dup
    13: iconst_1
    14: invokespecial #5                  // Method java/lang/Integer."<init>":(I)V
    17: invokeinterface #6,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z  类型擦除,存入Object类型的元素
    22: pop
    23: aload_1
    24: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
    29: astore_2
    30: aload_2
    31: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
    36: ifeq          49                  // 当栈顶int型数值等于0时跳转,hasNext返回0或1,上一期作业说过,jvm字节码没有布尔类型,True -> 1,False -> 0
    39: aload_2
    40: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    45: astore_3
    46: goto          30                  // 无条件跳转
    49: aload_1
    50: invokeinterface #7,  1            // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
    55: astore_2
    56: aload_2
    57: invokeinterface #8,  1            // InterfaceMethod java/util/Iterator.hasNext:()Z
    62: ifeq          78
    65: aload_2
    66: invokeinterface #9,  1            // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
    71: checkcast     #4                  // class java/lang/Integer
    74: astore_3
    75: goto          56
    78: return
    

    (3)结论

    • 泛型存入List时,进行类型擦除,将泛型转换为Object类型。
    • 从List中取出泛型时,需要类型检查和转换,Object -> 泛型。
    • 增强for循环实现原理,其实是编译器编译为iterator循环。

    (4)自己实现的List支持增强for循环吗?

    // 可以支持,但是必需实现Iterable接口,不然编译器不通过
    // 错误提示:for-each要求数组或者java.lang.Iterable
    public class MyArrayList<E> implements Iterable<E> {
    	// @Override注解,加不加无所谓,非强制
        @Override
        public Iterator<E> iterator() {
            return new ArrayIterator<>();
        }
    }
    

    (5)数组的增强for循环

    • JAVA代码
    int[] ints = new int[0];
    for (int i :ints){}
    
    • 字节码(这一段有点点复杂,冷静分析就好了,但是我不做过多的解释了,下面解释应该足够了。)
    0 iconst_1
    1 newarray 10 (int) // 创建一个指定原始类型(如int, float, char…)的数组,并将其引用值压入栈顶
    3 astore_1
    4 aload_1
    5 astore_2   //ints
    6 aload_2
    7 arraylength       // 获得数组的长度值并压入栈顶
    8 istore_3
    9 iconst_0          // 获取常数0
    10 istore 4         // 栈顶的值赋值给本地变量,0赋值给int
    12 iload 4
    14 iload_3
    15 if_icmpge 30 (+15)  // 比较栈顶两int型数值大小,当结果大于等于0时跳转
    18 aload_2   // 将第三个引用类型本地变量推送至栈顶,指的是ints
    19 iload 4   // 将指定的int型本地变量推送至栈顶,指的是i
    21 iaload
    22 istore 5  // 将栈顶int型数值存入指定本地变量,指的是tmp
    24 iinc 4 by 1 //将指定int型变量增加指定1
    27 goto 12 (-15)
    30 return
    
    • 翻译字节码为java代码
    int[] ints = new int[0];
    int length = ints.length;
    for (int i = 0; i - length < 0; i++){
        int tmp = ints[i];
    }
    
    • newarray 10 // 其中10代表类型

    参考:https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5.newarray

    Array Type atype
    T_BOOLEAN 4
    T_CHAR 5
    T_FLOAT 6
    T_DOUBLE 7
    T_BYTE 8
    T_SHORT 9
    T_INT 10
    T_LONG 11

    6 数组与List转换

    • 数组 => List:Arrays.asList(T[] arr)
    • List => 数组:list.toArray(T[] arr)
    Integer[] integers = new Integer[2];
    integers[0] = 1;
    integers[1] = Integer.valueOf(2);
    List<Integer> list = Arrays.asList(integers);
    Object[] objects = list.toArray();
    // 尽量不用,大部分jdk版本都运行时报错,只有少部分支持(1.8.0_171不报错)
    // Integer[] newInteger1 = (Integer[]) objects; 
    Integer[] newInteger2 = list.toArray(new Integer[list.size()]);
    System.out.println(Arrays.toString(newInteger2)); // [1, 2]
    

    二 线程安全的List

    1 Vector

    • 基本所有方法都用了synchronized,即用来对象锁,同一时刻只能有一个线程访问该对象。
    public synchronized void addElement(E obj) {
        modCount++;
        add(obj, elementData, elementCount);
    }
    
    public synchronized boolean removeElement(Object obj) {
        modCount++;
        int i = indexOf(obj);
        if (i >= 0) {
            removeElementAt(i);
            return true;
        }
        return false;
    }
    ......
    

    2 Collections.synchronizedList(ArrayList)

    • RandomAccess:空接口,只用于标识能够快速随机访问。
    // 快速随机访问重要表现:下标访问遍历 runs faster than 迭代器遍历:
    for (int i=0, n=list.size(); i < n; i++)
       list.get(i);
    
    for (Iterator i=list.iterator(); i.hasNext(); )
       i.next();
    
    • 根据是否实现RandomAccess接口,创建不同的线程安全集合
     public static <T> List<T> synchronizedList(List<T> list) {
         return (list instanceof RandomAccess ?
                 new SynchronizedRandomAccessList<>(list) :
                 new SynchronizedList<>(list));
     }
    
    // SynchronizedRandomAccessList继承了SynchronizedList
    static class SynchronizedRandomAccessList<E> extends SynchronizedList<E> implements RandomAccess {
    
        SynchronizedRandomAccessList(List<E> list) {
            super(list);
        }
    
        // ......
    }
    
    // SynchronizedList继承了SynchronizedCollection
    static class SynchronizedList<E> extends SynchronizedCollection<E> implements List<E> {
         private static final long serialVersionUID = -7754090372962971524L;
         final List<E> list;
    
        SynchronizedList(List<E> list) {
             super(list);
             this.list = list;
         }
        
         // ......
    }
    
    // 很明显对象锁,与Vector差不多,就是提供多一点的Api而已
    // 唯一不同就是mutex对象锁,可以外部指定,非必定为this对象
    static class SynchronizedCollection<E> implements Collection<E>, Serializable {
        private static final long serialVersionUID = 3053995032091335093L;
    
        final Collection<E> c;  // Backing Collection
        final Object mutex;     // Object on which to synchronize
    
        SynchronizedCollection(Collection<E> c) {
            this.c = Objects.requireNonNull(c);
            mutex = this;
        }
    
        SynchronizedCollection(Collection<E> c, Object mutex) {
            this.c = Objects.requireNonNull(c);
            this.mutex = Objects.requireNonNull(mutex);
        }
    
        public boolean add(E e) {
            synchronized (mutex) {return c.add(e);}
        }
        
        public boolean remove(Object o) {
            synchronized (mutex) {return c.remove(o);}
        }
        
        // ......
    }
    

    3 CopyOnWriteArrayList

    • 适用于读多写少,复制需要消耗一定的性能
    • 缺失了一定实时性,写过程中,其他线程读取到的都是旧值
    // java10
    public class CopyOnWriteArrayList<E> implements List<E>, RandomAccess, Cloneable, java.io.Serializable {
    
        /**
         * The lock protecting all mutators.  (We have a mild preference
         * for builtin monitors over ReentrantLock when either will do.)
         */
        // java8不是Object,而是ReentrantLock
        final transient Object lock = new Object();
    	
        private transient volatile Object[] array;
        
        // 读取操作不加锁
        public E get(int index) {
            return elementAt(getArray(), index);
        }
        
        @SuppressWarnings("unchecked")
        static <E> E elementAt(Object[] a, int index) {
            return (E) a[index];
        }
        
        // 写操作加对象锁
    	public boolean add(E e) {
            synchronized (lock) {
                Object[] elements = getArray();
                int len = elements.length;
                // CopyOnWrite的由来:由于读不加锁,我们希望在写过程中,读取多少次数据都得到相同结果,所以不对原来的数组进行修改,而是复制一份出来。
                Object[] newElements = Arrays.copyOf(elements, len + 1);
                newElements[len] = e;
                setArray(newElements); // array使用volatile修饰具有可见性,可以让其他读取线程马上知道
                return true;
            }
        }
        
        public E remove(int index) {
            synchronized (lock) {
                Object[] elements = getArray();
                int len = elements.length;
                E oldValue = elementAt(elements, index);
                int numMoved = len - index - 1;
                if (numMoved == 0)
                    setArray(Arrays.copyOf(elements, len - 1));
                else {
                    Object[] newElements = new Object[len - 1];
                    System.arraycopy(elements, 0, newElements, 0, index);
                    System.arraycopy(elements, index + 1, newElements, index,
                                     numMoved);
                    setArray(newElements);
                }
                return oldValue;
            }
        }
        
        // 无法重复加相同的元素,判断方法为equals方法
        // 但该方法不能用做set使用,因为它在内部是循环查询O(n),不是采用Hash命中O(1),效率差距很大
        public boolean addIfAbsent(E e) {
            Object[] snapshot = getArray();
            return indexOf(e, snapshot, 0, snapshot.length) >= 0 ? false :
                addIfAbsent(e, snapshot);
        }
        
        private boolean addIfAbsent(E e, Object[] snapshot) {
            synchronized (lock) {
                Object[] current = getArray();
                int len = current.length;
                if (snapshot != current) {
                    // Optimize for lost race to another addXXX operation
                    int common = Math.min(snapshot.length, len);
                    for (int i = 0; i < common; i++)
                        if (current[i] != snapshot[i]
                            && Objects.equals(e, current[i]))
                            return false;
                    if (indexOf(e, current, common, len) >= 0)
                            return false;
                }
                Object[] newElements = Arrays.copyOf(current, len + 1);
                newElements[len] = e;
                setArray(newElements);
                return true;
            }
        }
        
        // ......
    }
    
    • 重点介绍下复制方法
    // Arrays类
    @SuppressWarnings("unchecked")
    public static <T> T[] copyOf(T[] original, int newLength) {
        return (T[]) copyOf(original, newLength, original.getClass());
    }
    
    // Arrays类
    @HotSpotIntrinsicCandidate
    public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        @SuppressWarnings("unchecked")
        T[] copy = ((Object)newType == (Object)Object[].class)?
            (T[]) new Object[newLength] 
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));
        return copy;
    }
    
    // Array类
    public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException {
        return newArray(componentType, length);
    }
    
    // Array类
    @HotSpotIntrinsicCandidate
    private static native Object newArray(Class<?> componentType, int length) throws NegativeArraySizeException;
    
    // System类
    @HotSpotIntrinsicCandidate
    public static native void arraycopy(Object src,  int  srcPos,
                                        Object dest, int destPos,
                                        int length);
    
    // 稍微展示一下JVM中的TypeArray的copy_array
    // 在/hotspot/src/share/vm/oops/typeArrayKlass.cpp
    void TypeArrayKlass::copy_array(arrayOop s, int src_pos, arrayOop d, int dst_pos, int length, TRAPS) { 
      // ......
    
      // 前面都是异常检查,上下界检查,忽略即可,重要的是下面  
        
      // This is an attempt to make the copy_array fast.
      int l2es = log2_element_size();
      int ihs = array_header_in_bytes() / wordSize;
      char* src = (char*) ((oop*)s + ihs) + ((size_t)src_pos << l2es);
      char* dst = (char*) ((oop*)d + ihs) + ((size_t)dst_pos << l2es);
      Copy::conjoint_memory_atomic(src, dst, (size_t)length << l2es);
    }
    
    void Copy::conjoint_memory_atomic(void* from, void* to, size_t size) {
      address src = (address) from;
      address dst = (address) to;
      uintptr_t bits = (uintptr_t) src | (uintptr_t) dst | (uintptr_t) size;
    
      if (bits % sizeof(jlong) == 0) {
        Copy::conjoint_jlongs_atomic((jlong*) src, (jlong*) dst, size / sizeof(jlong));
      } else if (bits % sizeof(jint) == 0) {
        Copy::conjoint_jints_atomic((jint*) src, (jint*) dst, size / sizeof(jint));
      } else if (bits % sizeof(jshort) == 0) {
        Copy::conjoint_jshorts_atomic((jshort*) src, (jshort*) dst, size / sizeof(jshort));
      } else {
        // Not aligned, so no need to be atomic.
        Copy::conjoint_jbytes((void*) src, (void*) dst, size);
      }
    }
    
    // /hotspot/src/share/vm/utilities/copy.hpp
    static void conjoint_jbytes(void* from, void* to, size_t count) {
        pd_conjoint_bytes(from, to, count);
    }
    
    // 最后发现该方法与平台相关
    static void pd_conjoint_bytes(void* from, void* to, size_t count) {
    #ifdef AMD64
      (void)memmove(to, from, count);
    #else
      // Includes a zero-count check.
      intx temp;
      __asm__ volatile("        testl   %6,%6          ;"
                       "        jz      13f            ;"
                       "        leal    -1(%4,%6),%3   ;"
                       //...中间是一大段汇编代码,大家应该不感兴趣,省略
                       "        jbe     1f             ;"
                       "        addl    $3,%1          ;"
                       "11:     rep;    smovb          ;"
                       "12:     cld                    ;"
                       "13:     nop                    ;"
                       : "=S" (from), "=D" (to), "=c" (count), "=r" (temp)
                       : "0"  (from), "1"  (to), "2"  (count), "3"  (temp)
                       : "memory", "flags", "%edx");
    #endif // AMD64
    }
    
    // Class类:数组类型的Class才有返回值,返回数组存放的类型
    public Class<?> getComponentType() {
        // Only return for array types. Storage may be reused for Class for instance types.
        if (isArray()) {
            return componentType;
        } else {
            return null;
        }
    }
    
    // 简单测试一下
    
    // Test1:API的基本使用
    int[] src = {1,2,3,4,5,6,7,8,9,10};
    int[] des = new int[5];
    System.arraycopy(src,0,des,0,des.length);
    System.out.println(Arrays.toString(des)); // [1, 2, 3, 4, 5]
    
    // Test2:getComponentType方法
    System.out.println(int[].class.getComponentType()); //int
    System.out.println(Integer[].class.getComponentType()); //class java.lang.Integer
    
    // Test3
     System.out.println((Object) Object[].class == (Object) Object[].class);// true
     System.out.println((Object) Object[].class == (Object) Integer[].class);// false
    
    // Test4:Array.newInstance的作用:创建泛型数组创建并且强转不报错
    Integer[] objs = (Integer[]) Array.newInstance(Integer[].class.getComponentType(), 3);
    //  Integer[] objs = (Integer[]) new Object[3]; // 这里会报错,所以对于不是Object数组,不嫩那个使用new Object[length]的方式创建
    objs[0] = Integer.valueOf(1);
    objs[1] = Integer.valueOf(2);
    objs[2] = Integer.valueOf(3);
    System.out.println(Arrays.toString(objs));//[1, 2, 3]
    
  • 相关阅读:
    关于在MAC上进行 LARAVEL 环境 Homestead 安装过程记录
    js 贷款计算器
    js 实现阶乘
    js 两点间距离函数
    composer Your requirements could not be resolved to an installable set of packages
    vue 项目优化记录 持续更新...
    vue 项目打包
    vue 真机调试页面出现空白
    vue 真机调试
    谈谈-Android状态栏的编辑
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9571180.html
Copyright © 2011-2022 走看看