zoukankan      html  css  js  c++  java
  • ArrayList源码的 elementData.getClass() != Object[].class

    1. 放出源码

    2.  elementData与Object[]

      elementData的定义如下

    transient Object[] elementData; // non-private to simplify nested class access

      请看如下代码

    package test;
    
    public class UserTest2 {
        public static void main(String[] args) {
            User[] users = new User[]{
                    new User(1, "admin", "admin@qq.com"),
                    new User(2, "maco", "maco@qq.com"),
                    new User(3, "kitty", "kitty@163.com")
            };
    
            Object[] target = users;
            System.out.println(target.getClass());  // class [Ltest.User;
            target[0] = new Object();   // java.lang.ArrayStoreException: java.lang.Object
        }
    }

      显然直接将非Object[]类型数组赋予Object[]类型, 相当于将子类对象赋予父类变量, 这会导致什么问题呢,请看如下代码

    List<Object> list = new ArrayList<>(Arrays.asList("room", "take"));
    System.out.println(list.getClass());
    list.set(0, new Object());

      Arrays.asList("room", "take")返回的类型是String[](后面会解释, 注意这个BUG早就被修复了), 上面的代码显然会出错, 且错得莫名其妙, 我定义Object[]还不能存储Object实例了,显然是个BUG

    public class UserTest {
        public static void main(String[] args) {
            User[] users = new User[]{
                    new User(1, "admin", "admin@qq.com"),
                    new User(2, "maco", "maco@qq.com"),
                    new User(3, "kitty", "kitty@163.com")
            };
    
            Object[] objects = users;
            System.out.println(objects.getClass());         // class [Ltest.User;
            if(objects.getClass() != Object[].class){
                objects = Arrays.copyOf(objects, objects.length, Object[].class);   // class [Ljava.lang.Object;
            }
            System.out.println(objects.getClass());
        }
    }

      如上代码可知, 经过copyOf之后, 返回的类型是Object[], 就不会出现上述所说的错误了

    3. Arrays.asList干了什么?

        @SafeVarargs
        @SuppressWarnings("varargs")
        public static <T> List<T> asList(T... a) {
            return new ArrayList<>(a);
        }

      其调用的ArrayList不是java.util.ArrayList, 而是其内部类

    private static class ArrayList<E> extends AbstractList<E>
            implements RandomAccess, java.io.Serializable
        {
            private final E[] a;
    
            ArrayList(E[] array) {
                a = Objects.requireNonNull(array);
            }    
            // BUG实现
            @Override
            public Object[] toArray() {
                return a.clone();
            }
        
            
            // jdk-13.0.1的实现
           /*
            @Override
            public Object[] toArray() {
                return Arrays.copyOf(a, a.length, Object[].class);
            }
            */

      可运行以下代码测试

    System.out.println(new String[]{}.clone().getClass());  // class [Ljava.lang.String;

    4. Arrays.copyOf做了什么

        @SuppressWarnings("unchecked")
        public static <T> T[] copyOf(T[] original, int newLength) {
            return (T[]) copyOf(original, newLength, original.getClass());
        }
    
        @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;
        }
            Class newType = Object[].class;
            System.out.println(newType.getComponentType());     // class java.lang.Object

      数组的class对象的getComponentType()返回其元素组成类型, System.arraycopy进行数组复制(浅复制,复制引用)

    public static void main(String[] args) {
            User[] users = new User[]{
                    new User(1, "admin", "admin@qq.com"),
                    new User(2, "maco", "maco@qq.com"),
                    new User(3, "kitty", "kitty@163.com")
            };
    
            Object[] objects = users;
            System.out.println(objects.getClass());     // class [Ltest.User;
            objects = new Object[users.length];
            System.arraycopy(users, 0, objects, 0, Math.min(users.length, objects.length));
            System.out.println(objects.getClass());     // class [Ljava.lang.Object;
            System.out.println(objects[0] == users[0]); // true
        }

     5. 参考

    6.

  • 相关阅读:
    SFDC_08(翻页功能)
    SFDC-07(图形)
    SFDC_06(Data Loader)
    SFDC_05(内部类)
    SFDC_03(覆盖率)
    vue项目搭建
    vue语法01
    IDEA 的逆向工程 mybatis generate tool 的使用
    Git: Git: There is no tracking information for the current branch.
    Tomcat 不一定 需要配置环境变量(startup.bat 闪退原因及解决办法)
  • 原文地址:https://www.cnblogs.com/chenxingyang/p/11960038.html
Copyright © 2011-2022 走看看