JDK源码一句注释:c.toArray might (incorrectly) not return Object[] (see 6260652)

    xiaoxiao2025-04-19  8

    public ArrayList(Collection<? extends E> c) { elementData = c.toArray(); size = elementData.length; // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elementData.getClass() != Object[].class) elementData = Arrays.copyOf(elementData, size, Object[].class); } public CopyOnWriteArrayList(Collection<? extends E> c) { Object[] elements = c.toArray(); // c.toArray might (incorrectly) not return Object[] (see 6260652) if (elements.getClass() != Object[].class) elements = Arrays.copyOf(elements, elements.length, Object[].class); setArray(elements); }

    上网查了一下资料,才知道see 6260652 这个编号代表JDK bug库中的编号。可以去官网查看bug详情

    http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6260652

    http://bugs.java.com/bugdatabase/view_bug.do?bug_id=6515694

    6260652 和6515694这2个bug,貌似是同一个问题。这个bug是什么意思呢?我们先来看看一些测试代码:

    public static void test1() { SubClass[] subArray = {new SubClass(), new SubClass()}; System.out.println(subArray.getClass()); // class [Lcollection.SubClass; BaseClass[] baseArray = subArray; System.out.println(baseArray.getClass()); // java.lang.ArrayStoreException baseArray[0] = new BaseClass(); } public static void test2() { List<String> list = Arrays.asList("abc"); // class java.util.Arrays$ArrayList System.out.println(list.getClass()); // class [Ljava.lang.String; Object[] objArray = list.toArray(); System.out.println(objArray.getClass()); objArray[0] = new Object(); // cause ArrayStoreException } public static void test3() { List<String> dataList = new ArrayList<String>(); dataList.add("one"); dataList.add("two"); Object[] listToArray = dataList.toArray(); // class [Ljava.lang.Object;返回的是Object数组 System.out.println(listToArray.getClass()); listToArray[0] = ""; listToArray[0] = 123; listToArray[0] = new Object(); }

    1、关于test1()

            SubClass 继承自BaseClass,由于SubClass数组中每一个元素都是SubClass对象,所以BaseClass[] baseArray = subArray;这种强制类型转换不会报错。其实就是java对象的向上转型,子类数组转换成父类数组是允许的。但是由于数组中元素类型都是SubClass类型的,所以 baseArray[0] = new BaseClass();会报错java.lang.ArrayStoreException。这也就是说假如我们有1个Object[]数组,并不代表着我们可以将Object对象存进去,这取决于数组中元素实际的类型。

    2、关于test2()

      List<String> list = Arrays.asList("abc");需要注意,可以知道返回的实际类型是java.util.Arrays$ArrayList,而不是ArrayList。我们调用

          Object[] objArray = list.toArray();返回是String[]数组,所以我们不能将Object对象,放到objArray数组中。

    3、关于test3()

    ArrayList对象的toArray()返回就是Object[]数组,所以我们可以将任意对象存放到返回的Object[]数组中。

    通过test2和test3可以看出,如果我们有1个List<String> stringList对象,当我么调用Object[] objectArray = stringList.toArray();的时候,objectArray 并不一定能够放置Object对象。这就是源码中的注释:c.toArray might (incorrectly) not return Object[] (see 6260652)。为了考虑这种情况,所以源码中进行了if判断,来防止错误的数组对象导致异常。Arrays.copyOf(elementData, size, Object[].class);这个方法就是用来创建1个Object[]数组,这样数组中就可以存放任意对象了。

    当我们调用ArrayList中的 toArray(),可能遇到过抛出“java.lang.ClassCastException”异常的情况。下面我们说说这是怎么回事。

    ArrayList提供了2个toArray()函数:

    Object[] toArray() <T> T[] toArray(T[] contents)

    调用 toArray() 函数会抛出“java.lang.ClassCastException”异常,但是调用 toArray(T[] contents) 能正常返回 T[]。

    toArray() 会抛出异常是因为 toArray() 返回的是 Object[] 数组,将 Object[] 转换为其它类型(如如,将Object[]转换为的Integer[])则会抛出“java.lang.ClassCastException”异常,因为Java不支持向下转型。具体的可以参考前面ArrayList.java的源码介绍部分的toArray()。 解决该问题的办法是调用 <T> T[] toArray(T[] contents) , 而不是 Object[] toArray()。

    调用 toArray(T[] contents) 返回T[]的可以通过以下几种方式实现。

    // toArray(T[] contents)调用方式一 public static Integer[] vectorToArray1(ArrayList<Integer> v) { Integer[] newText = new Integer[v.size()]; v.toArray(newText); return newText; } // toArray(T[] contents)调用方式二。最常用! public static Integer[] vectorToArray2(ArrayList<Integer> v) { Integer[] newText = v.toArray(new Integer[0]); return newText; } // toArray(T[] contents)调用方式三 public static Integer[] vectorToArray3(ArrayList<Integer> v) { Integer[] newText = new Integer[v.size()]; Integer[] newStrings = v.toArray(newText); return newStrings; }
    转载请注明原文地址: https://ju.6miu.com/read-1298229.html
    最新回复(0)