ArrayStoreException

最近看到一段JDK中ArrayList类中的源码,其中一段注释吸引了我的眼球,为了弄清其含义,特意找了一些资料,写了一点测试代码。源代码如下:

/**
 * Constructs a list containing the elements of the specified
 * collection, in the order they are returned by the collection's
 * iterator.
 *
 * @param c the collection whose elements are to be placed into this list
 * @throws NullPointerException if the specified collection is null
 */
public ArrayList(Collection<? extends E> c) {
    elementData = c.toArray();
    if ((size = elementData.length) != 0) {
        // c.toArray might (incorrectly) not return Object[] (see 6260652)
        if (elementData.getClass() != Object[].class)
            elementData = Arrays.copyOf(elementData, size, Object[].class);
    } else {
        // replace with empty array.
        this.elementData = EMPTY_ELEMENTDATA;
    }
}
为了弄清楚 // c.toArray might (incorrectly) not return Object[] (see 6260652) 这句注释的意义,特意查了一下官方的bug文档,Bug ID:JDK-6260652,地址如下

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


官方文档上有这样一段描述

 
A DESCRIPTION OF THE PROBLEM :
The Collection documentation claims that

    collection.toArray()

is "identical in function" to

    collection.toArray(new Object[0]);

However, the implementation of Arrays.asList does not follow this: If created with an array of a subtype (e.g. String[]), its toArray() will return an array of the same type (because it use clone()) instead of an Object[].

If one later tries to store non-Strings (or whatever) in that array, an ArrayStoreException is thrown.

用我稀烂的英语翻译了一下就是:

该问题的描述
Collection文档上是这样声称的
toArray(new Object[0])函数和toArray()是相同的。
然而,Arrays.asList的实现并不遵循这一点:如果用子类创建了一个数组,比方说String[]数组,它的toArray()方法将返回一个相同类型的数组(因为使用了clone()方法)而不是一个Object[]数组。

如果后来试图存储一个非String类型(或者其他类型)的数据到这个数组中,就会抛出ArrayStoreException 。


为此我特意翻看了JDK中Collection接口的API文档,确实有那么一句描述



通过API文档发现这两个方法并不是完全一致

Object[] toArray()
<T> T[] toArray(T[] a)
一个返回的是确定的Object[]数组,另一个是泛型,根据运行时的类型来确定。

结合JDK的API文档和官方的bug文档,基本可以确定就返回类型导致抛出ArrayStoreException。


接下来写了2个测试的例子:

public static void main(String[] args) {
    String[] array = {"a","b"};
    Object[] o = array;
    System.out.println(o.getClass());
    o[0] = new Object();
}
运行结果:

class [Ljava.lang.String;
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Object

在第一个例子中将String[]类型的数组向上转型成为Object[]数组,而真正在运行时,打印出来该数组的实际类型依旧是String[]数组,之后向该数组中插入一个Object类型的元素时,抛出异常。


public static void main(String[] args) {
    List<String> list = Arrays.asList("a","b");
    System.out.println(list.getClass());
    Object[] o = list.toArray();
    System.out.println(o.getClass());
    o[0] = new Object();
}
运行结果:

class java.util.Arrays$ArrayList
class [Ljava.lang.String;
Exception in thread "main" java.lang.ArrayStoreException: java.lang.Object

在第二个例子中声明了一个List<String>的集合,运行时得到的是Arrays的内部类ArrayList类型,通过toArray()方法后,实际得到的是String[]数组,也不是Object[]数组,之后插入元素的时候抛出异常。


正因为运行时可能会出现ArrayStoreException,ArrayList类中判断了数组类型不是Object类型时,新建了一个Object[]数组,已保证不会出现异常

// c.toArray might (incorrectly) not return Object[] (see 6260652)
if (elementData.getClass() != Object[].class)
    elementData = Arrays.copyOf(elementData, size, Object[].class);

  • 13
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值