ArrayList源码之6260652 bug号

ArrayList源码之6260652 bug号

List的toArray()方法有多个实现,主要关注两个。原因是分析ArrayList源码时,解决构造方法中的“c.toArray might (incorrectly) not return Object[] (see 6260652)”注释。

ArrayList的构造方法源码

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;
        }
    }

源码中为何有“if (elementData.getClass() != Object[].class)”判断呢?
因为elementData = c.toArray();有两种类型的返回,一个是Object[] 类型,一个是具体的数组类型(如Integer[])。

  • 如果c.toArray()返回的类型是Object[]时,则不需要转换,直接使用(因为源码中transient Object[]
    elementData就是存List数据的数组,类型符合要求);
  • 如果c.toArray()返回的类型是Intger[]时,则需要转化为Object[]类型;

验证c.toArray()方法会返回两种类型的数组这一现象

测试代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestMain {
    public static void main(String[] args) {
        testBug6260652();
//        testBug6260652GZ();
        //      testBug6260652GZ2();
    }

    /**
     * 测试toArray方法返回类型
     * c.toArray might (incorrectly) not return Object[] (see 6260652)
     */
    private static void testBug6260652(){
        Integer[] array={1,2};
        //通过Arrays.asList转换,保留了原来的基本类型
        List list= Arrays.asList(array);
        //转换后的数组
        Object[] array3=list.toArray();
        System.out.println("转换后的数组:"+array3.getClass());
        System.out.println(array3.getClass()==Object[].class);
        List<Integer> newList=new ArrayList<Integer>();
        newList.add(4);
        System.out.println("new ArrayList 转换后数组类型:"+newList.toArray());
        System.out.println(newList.toArray().getClass()==Object[].class);
    }
}

测试方法打印结果
转换后的数组:class [Ljava.lang.Integer;
false
new ArrayList 转换后数组类型:[Ljava.lang.Object;@71bc1ae4
true
总结现象

通过下面的代码,toArray方法返回的是Integer[]

 		Integer[] array={1,2};
        //通过Arrays.asList转换,保留了原来的基本类型
        List list= Arrays.asList(array);
        //转换后的数组
        Object[] array3=list.toArray();

通过下面的代码,toArray方法返回的是Object[]

在这里插入代码片List<Integer> newList=new ArrayList<Integer>();
        newList.add(4);
        System.out.println("new ArrayList 转换后数组类型:"+newList.toArray());
        System.out.println(newList.toArray().getClass()==Object[].class);

综上所述,toArray方法确实会返回两种类型的数组,也就理解了ArrayList源码中为何有“c.toArray might (incorrectly) not return Object[] (see 6260652)”这段注释以及下面的判断逻辑。

结合ArrayList源码分析

总结上面的测试方法,已经可以确定toArray方法返回两种类型的数组。那么结合ArrayList源码继续分析,构造方法中“c.toArray might (incorrectly) not return Object[] (see 6260652)”这段注释的原因。

测试代码
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class TestMain {
    public static void main(String[] args) {
//        testBug6260652();
        testBug6260652GZ();
        testBug6260652GZ2();
    }

    /**
     * toArray方法返回Integer[]数组,测试构造方法
     */
    private static void testBug6260652GZ(){
        Integer[] array={1,2};
        //通过Arrays.asList转换,保留了原来的基本类型
        List list= Arrays.asList(array);
        List list2 =new ArrayList<>(list);
        System.out.println(list);
        System.out.println(list2);
    }
    /**
     * toArray方法返回Object[]数组,测试构造方法
     */
    private static void testBug6260652GZ2(){
        List<Integer> newList=new ArrayList<Integer>();
        newList.add(4);
        List list2 =new ArrayList<>(newList);
        System.out.println(newList);
        System.out.println(list2);
    }
}

调试main方法进行分析

testBug6260652GZ方法中进入ArrayList构造方法时,elementData的类型是Integer[],if (elementData.getClass() != Object[].class)这个判断为true。

public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();//返回的是Integer[]
        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;
        }
    }

testBug6260652GZ2方法中进入ArrayList构造方法时,elementData的类型是Object[],if (elementData.getClass() != Object[].class)这个判断为false。

在这里插入代码片public ArrayList(Collection<? extends E> c) {
        elementData = c.toArray();//返回的是Object[]
        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)”这段注释的原因是elementData = c.toArray()返回的类型可能是Object[],也可能是具体的数组类型,如Integer[]。

为何toArray会返回两种数组类型呢?

依旧用上述测试代码进行调试,跟踪 elementData = c.toArray()中toArray方法的实现。
当从testBug6260652GZ方法入口进入构造时,断点如下图:
在这里插入图片描述

当从testBug6260652GZ2方法入口进入构造时,断点如下图:
在这里插入图片描述
结合上面两张图可以看到,两个方法分别进入两个实现:

  • Object[] Arrays$ArrayList.toArray() :Arrays的内部类ArrayList的方法
  • Object[] ArrayList.toArray():java.util.ArrayList的方法

为何会出现两个实现呢?
因为List list= Arrays.asList(array);返回的是Arrays.ArrayList,而 List newList=new ArrayList();返回的是java.util.ArrayList

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值