java之ArrayList的toArray方法

ArrayList是Java在中使用频率非常高的一个方法。我们在使用ArrayList的时候,经常需要将ArrayList中的对象转换为一个数组。

java已经对ArrayList进行了很好的封装,只需要调用ArrayList的toArray方法就可以从ArrayList对象中提取存放的对象的数组。

ArrayList重载了如下两个toArray方法:

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

public <T> T[] toArray(T[] a) {
         if (a.length < size)
             return (T[]) Arrays.copyOf(elementData, size, a.getClass());
 
         System.arraycopy(elementData, 0, a, 0, size);
         if (a.length > size)
             a[size] = null;
         return a;
     }

初学者在这两个方法的使用上获取会遇到一些困惑。下面结合笔者自己学习过程中遇到的困惑为大家详细介绍这两个toArray方法。

笔者在初学的时候在网络上看到过如下的简单代码

  ArrayList list1 = new ArrayList();
  System.out.println("size: " + list1.size());
  for(int i=0; i<20; i++){
   list1.add("hello");
  }
  String[] str = (String[])list1.toArray();
 上面的代码先构造了一个ArrayList对象,然后往里面填了20个String对象,最后希望将ArrayList中的对象转换成一个数组。

执行上面的代码会报如下异常

[Ljava.lang.Object; cannot be cast to [Ljava.lang.String;


toArray()方法返回的数组为Object数组。上面的代码将Object数组强制转换为了String数组,属于将父类的引用强制转化为子类的引用。
java中,这种父类引用强制转化为子类引用只有在父类的引用指向的真实对象类型为所要强制转化的子类类型的时候,才不会报错。
下面举个小例子说明一下。

class Father{
	String name;
	int age;
	
}
class Son extends Father{
	String girlFriend;
}
class Daughter extends Father{
	String boyFriend;
}


public class test{
	public static void main(String[] args)
	{
		Father f = new Son();
		Son s = (Son)f;
		
		Daughter d = (Daughter)f;
		
		Father f2 = new Father();
		Son s2 = (Son)f2;
		
	}
}

String[] str = (String[])list1.toArray();报错很可能是由于toArray()方法返回的对象所指向的真实类型就是Object数组。

Arrays.copyOf(elementData, size)方法的源代码为

 

public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {  
    T[] copy = ((Object)newType == (Object)Object[].class)  
        ? (T[]) new Object[newLength]  
        : (T[]) Array.newInstance(newType.getComponentType(), newLength);  
    System.arraycopy(original, 0, copy, 0,  
                     Math.min(original.length, newLength));  
    return copy;  
}  
public static <T> T[] copyOf(T[] original, int newLength) {  
return (T[]) copyOf(original, newLength, original.getClass());  
}  


观察发现,当不指定拷贝的数据类型的时候,copyOf将直接使用数据源的数据类型进行对象的拷贝。

查看ArrayList的源代码可以看到elementData的定义为

private transient Object[] elementData;
因此,toArray()方法返回的对象的真实类型为Object[ ],因此无法将类型强制转化为String [],即便是ArrayList使用了泛型,也不能进行类似的强制类型转换。

我们一般通过toArray(T[] contents)方法将ArrayList转化为一个目标类型的数组

//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 = (Integer[])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 = (Integer[])v.toArray(newText);
 return newStrings;
}


public <T> T[] toArray(T[] a) {
         if (a.length < size)
             return (T[]) Arrays.copyOf(elementData, size, a.getClass()); # 方法二
 
         System.arraycopy(elementData, 0, a, 0, size); # 方法一和方法三
         if (a.length > size)
             a[size] = null;
         return a;
     }

其中,第一种方法和第三种方法都是利用了toArray(T[] contents)方法中的System.arraycopy语句进行数组的拷贝。由于System.arraycopy直接改变了

目标数组引用的内容,因此可以像方法一一样,不需要定义toArray方法的返回值,再将返回值返回,而是可以直接返回目标数组。

方法二则是使用了toArray(T[] contents)方法中Array.copyOf语句重新创建了一个目标类型的数组。

由于方法二的语句更加简洁,因此方法二更为常用。





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值