java集合转数组(Collection转array)

本文探讨了Java集合框架中Collection接口的toArray()方法,详细解析了无参和有参版本的用法及注意事项。无参版本可能导致ClassCastException,而有参版本在数组大小与集合大小不匹配时有不同的处理方式。通过源码分析,揭示了当数组大小小于集合时,会通过反射创建新数组,虽然仍能正确转换,但会影响性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在JDK内置的集合框架中,Collection接口提供了集合转数组的的两个方法

  • Object[] toArray();
  • <T> T[] toArray(T[] a);

     

对于无参的toArray()函数,其返回值类型为Object[] ,此时不能强制转换成其他类型,若强转将会抛出ClassCastException异常

代码测试

package basicKnowledge.集合框架.treeset;

import java.util.TreeSet;

/**
 * @基本功能:
 * @program:summary
 * @author:peicc
 * @create:2019-08-01 11:10:16
 **/
public class TestTreeSet {
    public static void main(String[] args) {
        testTreeSetAPIS();
    }
    public static void testTreeSetAPIS(){
        TreeSet treeSet=new TreeSet();
        //测试集合的有序性
        treeSet.add("aaa");
        treeSet.add("bbb");
        treeSet.add("eee");
        treeSet.add("ddd");
        String array1[]=(String[])treeSet.toArray();
        for (Object object:array1) {
            System.out.printf("for each:%s\n",object);
        }
    }
}

 运行结果

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;
	at basicKnowledge.集合框架.treeset.TestTreeSet.testTreeSetAPIS(TestTreeSet.java:45)
	at basicKnowledge.集合框架.treeset.TestTreeSet.main(TestTreeSet.java:13)

因此,对于集合转数组,我们通常采用第二种有参的函数,但此时我们需要关注下传递的参数:

  • 第一种情况:传递的数组大小等于集合的大小
  • 第二种情况:传递的数组大小大于集合的大小
  • 第三种情况:传递的数组大小小于集合的大小

代码测试

public static void testToArray(){
        TreeSet treeSet=new TreeSet();
        //测试集合的有序性
        treeSet.add("chang");
        treeSet.add("cheng");
        treeSet.add("ge");
        //数组大小等于集合大小
        System.out.println("-------------数组大小等于集合大小------------------");
        String array1[]=(String[])treeSet.toArray(new String[treeSet.size()]);
        System.out.println(array1.length);
        for(String str:array1){
            System.out.printf("for each:%s\n",str);
        }
        //数组大小小于集合大小
        System.out.println("-------------数组大小小于集合大小------------------");
        String array2[]=(String[])treeSet.toArray(new String[0]);
        System.out.println(array2.length);
        for(String str:array2){
            System.out.printf("for each:%s\n",str);
        }
        //数组大小大于集合大小
        System.out.println("-------------数组大小大于集合大小------------------");
        String array3[]=(String[])treeSet.toArray(new String[10]);
        System.out.println(array3.length);
        for(String str:array3){
            System.out.printf("for each:%s\n",str);
        }
    }

运行结果

-------------数组大小等于集合大小------------------
3
for each:chang
for each:cheng
for each:ge
-------------数组大小小于集合大小------------------
3
for each:chang
for each:cheng
for each:ge
-------------数组大小大于集合大小------------------
10
for each:chang
for each:cheng
for each:ge
for each:null
for each:null
for each:null
for each:null
for each:null
for each:null
for each:null

Process finished with exit code 0

 对于第一种、第三种情况我们或许能理解,但对于第二种情况,当我们传进大小为0的数组时,为什么也能将集合正常转换成数组?我初步猜测是因为当我们将数组引用传递进去的时候,该方法会对数组的长度与集合的长度进行判断,然后再进行转换。于是,进一步我变通过源码分析验证了我的猜想。

    public <T> T[] toArray(T[] a) {
        // Estimate size of array; be prepared to see more or fewer elements
        int size = size();
        T[] r = a.length >= size ? a :
                  (T[])java.lang.reflect.Array
                  .newInstance(a.getClass().getComponentType(), size);
        Iterator<E> it = iterator();

        for (int i = 0; i < r.length; i++) {
            if (! it.hasNext()) { // fewer elements than expected
                if (a == r) {
                    r[i] = null; // null-terminate
                } else if (a.length < i) {
                    return Arrays.copyOf(r, i);
                } else {
                    System.arraycopy(r, 0, a, 0, i);
                    if (a.length > i) {
                        a[i] = null;
                    }
                }
                return a;
            }
            r[i] = (T)it.next();
        }
        // more elements than expected
        return it.hasNext() ? finishToArray(r, it) : r;
    }

通过源码,我们可以看见,当数组的长度小于集合大小时,通过反射机制重新构造一个与集合大小相同的数组。当数组的长度大于集合大小时,返回的数组长度为传进去的数组长度,多余元素以null填充

结论

  • 集合转数组时,请使用带参数的toArray()方法,并且传进去的参数类型与大小请与集合的元素类型与大小一致
  • 虽然当传递进去的数组大小小于集合大小时,也能得到正确结果,但经过反射生成数组需要花费一些时间,对性能有些许影响 
        long start=System.currentTimeMillis();
        for (int i = 0; i <100000 ; i++) {
            String array4[]=(String[])treeSet.toArray(new String[0]);
        }
        long end=System.currentTimeMillis();
        System.out.println("用时:"+(end-start));
        start=System.currentTimeMillis();
        for (int i = 0; i <100000; i++) {
            String array5[]=(String[])treeSet.toArray(new String[treeSet.size()]);
        }
        end=System.currentTimeMillis();
        System.out.println("用时:"+(end-start));

时间相差两至三倍

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值