ArrayList 有参构造函数中的c.toArray might (incorrectly) not return Object[] (see 6260652)问题理解

问题:

     在走读ArrayList参数为Collection类型的有参构造函数时,发现构造函数把参数转换成数组并赋值给成员变量elementData后,又进行了elementData.getClass() != Object[].class判断,并在条件为true的时候又进行了一次转换,并在该处说明c.toArray might (incorrectly) not return Object[] (see 6260652),具体代码如下:

   public ArrayList(Collection<? extends E> c) {
		//将构造方法中的参数转成数组,如果参数为空则会报NullPointerException异常
        elementData = c.toArray();
		//elementData长度值赋给size,也就是说此时ArrayList它包含的元素数为传过来集合转换为数组的长度
		//判断elementData.length是否不等于0
        if ((size = elementData.length) != 0) {
			//如果不等于0,并且这个数组的类型不是Object[],那么将他转化成Object[]
            // c.toArray might (incorrectly) not return Object[] (see 6260652)  这句话大概的意思是c.toArray()有可能返回的不是Object[] 类型
			//加上这个判断可以及转换就是为了解决这个bug
            if (elementData.getClass() != Object[].class)
                elementData = Arrays.copyOf(elementData, size, Object[].class);
        } else {
		     //如果elementData.length等于0则 elementData元素被赋值为 EMPTY_ELEMENTDATA
            // replace with empty array.
			// 替换为空数组。
            this.elementData = EMPTY_ELEMENTDATA;
        }
    }

c.toArray might (incorrectly) not return Object[] (see 6260652)  这句话大概的意思是c.toArray()有可能返回的不是Object[] 类型,并说明这个JDKbug的编号是6260652

研究:

      c.toArray()这个方法是在Collection这个接口中定义,具体实现需要Collection接口的实现类自己实现

Object[] toArray();

这里我们看一下ArrayList内部是怎么实现该方法的

public Object[] toArray() {
     return Arrays.copyOf(elementData, size);
}

这里的elementData是ArrayList中的定义的一个Object[]类型成员变量,经过Arrays.copyOf()转换后还是这个Object[]的(具体Arrays.copyOf()内部机制有兴趣可以再研究),那么针对如果所有的Collection接口的集合中toArray()都是这样的,那么就不会出现这个BUG了。看一下如下代码:

public static void main(String[] args) {
        List<String> abc = Arrays.asList("abc","def");
        
        System.out.println(abc); //[abc, def]
        System.out.println(abc.getClass()); //class java.util.Arrays$ArrayList

        Object[] objects = abc.toArray();

        System.out.println(objects.getClass());//class [Ljava.lang.String;

        System.out.println(objects.getClass() == Object[].class);//false


        objects[0] = "aaa";

        System.out.println(objects[0]); //aaa


        objects[0] = 123; 
        // Exception in thread "main" java.lang.ArrayStoreException: java.lang.Integer
       // at com.lcg.collection.arryList.code.ConstructsStudy.main(ConstructsStudy.java:27)

        System.out.println(objects[0]);
 
    }

  通过代码中注释的结果可以看出,经过Arrays.asList获取的集合为class java.util.Arrays$ArrayList注意这个ArrayList为Arrays类中的内部类,而这个类toArray方法返回的是[Ljava.lang.String类型,这个与Object[].class不同,而这样会出什么问题呢?继续看上边的代码如果我在toArray或者的集合中进行数据替换如果替换的是字符串那一切正常,如果我替换的是非字符串,比如是数字,那么程序就会报出异常。

而ArrayList中是要任何类型的数据都可以存放的(不考虑泛型,只从数据存储层面讲),所以为了避免这个问题,ArrayList在参数为Collection类型的有参构造函数中添加了类型判断及类型转换

总结:

   估计一开始是想让Collection的实现类的toArray方法返回Object类型,这样是符合集合的概念,就是集合可以存放任何类型的数据,但是从泛型出现后,可能对存入的数据进行了规范从而导致这个问题。

    

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值