作业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]
作业12:List集合类的更多相关文章
- | C语言I作业12
		C语言I作业12-学期总结 标签:18软件 李煦亮 问题 答案 这个作业属于那个课程 C语言程序设计I 这个作业要求在哪里 https://edu.cnblogs.com/campus/zswxy/S ... 
- C语言Ⅰ作业12—学期总结
		一.我学到的内容 二.我的收获 作业链接 收获 C语言Ⅰ博客作业01 认识了PTA编程,博客园,Markdown基本语法1,Markdown基本语法2 C语言Ⅰ博客作业02 PTA系统常见问题解答 C ... 
- C语言I作业12—学期总结
		一.我学到的内容 二我的收获 作业 收获 C语言博客作业1 刚开始初步了解C语言方面的知识 学会Markdown基本语法 C语言博客作业2 学会了应该如何提问 PTA系统常见问题解答 学会了MinGW ... 
- 作业——12 hadoop大作业
		作业的要求来自于:https://edu.cnblogs.com/campus/gzcc/GZCC-16SE2/homework/3339 Hadoop综合大作业 1.以下是爬虫大作业产生的csv文件 ... 
- C语言I作业12一学期总结
		一.我学到的内容 二.我的收获 作业 收获 C语言I博客作业01 学会了编程"Hello word" C语言I博客作业02 安装编译器,将代码建立在自己的文件里面 C语言I博客作业 ... 
- C语言I博客作业12—学期总结
		一.我学到的内容 二.我的收获(包括我完成的所有作业的链接+收获)不能只有作业链接,没有收获 作业次数 作业链接 第一次 C语言I博客作业01 第二次 C语言I博客作业02 第三次 C语言I博客作业0 ... 
- C语言|作业12—学期总结
		一. 我学到的内容 二. 我的收获 作业链接 收获 C语言l博客作业01 对这个专业.学科以及markdown语法有了初步了解,打印出了"Hello world!" C语言l博客作 ... 
- C语言|博客作业12—学期总结
		一.我学到的内容 二.我的收获 (1)https://edu.cnblogs.com/campus/zswxy/CST2019-4/homework/7603 收获:第一次接触C语言和写博客,感觉特别 ... 
- C语言I博客作业12
		一.我学到的内容 二.我的收获 作业链接 收获 博客第一次作业:https://www.cnblogs.com/gm12/p/11584148.html 第一次作业收获:第一次作业是我初步接触C语言的 ... 
随机推荐
- html文字两行后,就用省略号代替剩下的
			html文字两行后,就用省略号代替剩下的 一.总结 一句话总结: 实现原理很简单,将box的高度设置为行高的两倍,超出之后隐藏,这样就只有两行了,然后再用after属性绝对定位在第二行后面加几个点 . ... 
- distinct 排除重复 函数
			select count(distinct uid) from ib_user_settings; 参考: http://www.w3school.com.cn/sql/sql_distinct.as ... 
- [Scikit-learn] Yield miniBatch for online learning.
			From: Out-of-core classification of text documents Code: """ ======================= ... 
- Vue input 控件: 通过自定义指令(directive)使用正则表达式限制input控件的输入
			前言: 网站中的input输入框使用非常广泛,因业务场景不同需要对输入框做合法性校验或限制输入,比如电话号码.邮件.区号.身份证号等.input框的不合法内容主要有两种方式处理:1.用户输入内容后,通 ... 
- Zabbix 3.4.3 使用阿里云短信服务进行报警
			目录 一.阿里云短信服务 1.1.首先开通阿里云短信服务 1.2 创建签名 1.3 创建短信模板 1.4 创建发送脚本 二.Zabbix Web 配置 2.1 增加 Media types 2.2 给 ... 
- RabbitMQ简单实现,exchange四种模式,持久化
			RabbitMQ目录 一.简介,简单实现二.Exchange四种类型简单介绍三.消息确认,交换机.队列及消息持久化一.简介及简单实现RabbitMQ是一个消息代理:它接受并转发消息.你可以把它当成一个 ... 
- (转载)如何创建一个以管理员权限运行exe 的快捷方式? How To Create a Shortcut That Lets a Standard User Run An Application as Administrator
			How To Create a Shortcut That Lets a Standard User Run An Application as Administrator by Chris Hoff ... 
- tf.contrib.layers.fully_connected参数笔记
			tf.contrib.layers.fully_connected 添加完全连接的图层. tf.contrib.layers.fully_connected( inputs, num_ou ... 
- 最新  竞技世界java校招面经 (含整理过的面试题大全)
			从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.竞技世界等10家互联网公司的校招Offer,因为某些自身原因最终选择了竞技世界.6.7月主要是做系统复习.项目复盘.Leet ... 
- 最新 朗玛信息java校招面经 (含整理过的面试题大全)
			从6月到10月,经过4个月努力和坚持,自己有幸拿到了网易雷火.京东.去哪儿.朗玛信息等10家互联网公司的校招Offer,因为某些自身原因最终选择了朗玛信息.6.7月主要是做系统复习.项目复盘.Leet ... 
