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]
    
  • 相关阅读:
    幕客前端基础入门-html表单
    幕客前端基础入门-html表格
    幕客前端基础入门-html基础
    尚硅谷nginx教程-7nginx原理
    尚硅谷nginx教程-7nginx配置示例-配置高可用的集群
    尚硅谷nginx教程-6nginx配置示例-动静分离
    尚硅谷nginx教程-5nginx配置示例-负载均衡
    尚硅谷nginx教程-4nginx配置示例-反向代理
    尚硅谷nginx教程-3nginx常用命令和配置文件
    尚硅谷nginx教程-1nginx简介
  • 原文地址:https://www.cnblogs.com/linzhanfly/p/9571180.html
Copyright © 2011-2022 走看看