ArrayList.toArray()

本文解析了ArrayList.toArray()方法的工作原理及可能出现的java.lang.ClassCastException错误原因,并提供了两种解决方案:使用trimToSize()调整数组大小或指定目标数组。

ArrayList.toArray()时,出现java.lang.ClassCastException的错误。

ArrayList类扩展AbstractList并执行List接口。ArrayList支持可随需要而增长的动态数组。

    ArrayList有如下的构造函数:
        ArrayList( )
        ArrayList(Collection c)
        ArrayList(int capacity)

如果调用new ArrayList()构造时,其默认的capacity(初始容量)为10。

参见ArrayList源码,其中是这样定义的:

    public ArrayList() {
  this(10);
     }

默认初始化内部数组大小为10。

程序编译后执行ArrayList.toArray(),把ArrayList转化为数组时,该数组大小仍为capacity(为10)。

当装入的数据和capacity值不等时(小于capacity),比如只装入了5个数据,数组中后面的(capacity - size)个对象将置为null,此时当数组强制类型转换时,容易出现一些问题,如java.lang.ClassCastException异常等。

解决办法是:

1.在用ArrayList转化为数组装数据后,使用trimToSize()重新设置数组的真实大小。

2.String[] myStringArray = (String[])ArrayList.toArray(new String[0]);   //注意此处的写法

public Object[] toArray() {
  Object[] result = new Object[size];
  System.arraycopy(elementData, 0, result, 0, size);
  return result;
}

返回ArrayList元素的一个数组,注意这里虽然生成了一个新的数组,但是数组元素和集合中的元素是共享的,Collection接口中说这个是安全的,这是不严格的。

下面的例子演示了这个效果。
   ArrayList al=new ArrayList();
   al.add(new StringBuffer("hello"));
   Object[] a=al.toArray();
   StringBuffer sb=(StringBuffer)a[0];
   sb.append("changed");  //改变数组元素同样也改变了原来的ArrayList中的元素
   System.out.println(al.get(0));    

这里不要用String来代替StringBuffer,因为String是常量。

ArrayList.toArray()之二:

public Object[] toArray(Object a[]) {
  if (a.length < size)
    a = (Object[])java.lang.reflect.Array.newInstance(a.getClass().getComponentType(), size);
   System.arraycopy(elementData, 0, a, 0, size);
   if (a.length > size)
      a[size] = null;
   return a;
}

这个方法有可能不需要生成新的数组,注意到如果数组a容量过大,只在size处设置为null。

如果这个数组a足够大,就会把数据全放进去,返回的数组也是指向这个数组,(数组多余的空间存储的是null对象);要是不够大,就申请一个跟参数同样类型的数组,把值放进去,然后返回。

### 问题分析 在 Java 中,使用 `ArrayList<Integer[]>` 转换为 `int[][]` 时出现 `ArrayStoreException` 的根本原因在于类型不匹配。`ArrayList.toArray(T[] a)` 方法要求传入的数组类型必须是集合元素类型的超类型[^4]。由于 `Integer[]` 与 `int[][]` 类型不兼容,直接转换会导致运行时异常。 此外,当实现区间合并功能时,通常使用 `List<int[]>` 来存储区间,最终需要将其转换为 `int[][]` 返回。因此,正确的做法是手动遍历 `List<int[]>` 并将每个元素复制到目标二维数组中,而不是依赖 `toArray()` 方法。 ### 解决方案 为避免 `ArrayStoreException`,应避免将 `Integer[]` 转换为 `int[][]`。对于 `List<int[]>`,可以使用如下方式将其转换为 `int[][]`: ```java List<int[]> intervals = new ArrayList<>(); // 添加区间,例如 intervals.add(new int[]{1, 3}); int[][] result = new int[intervals.size()][]; for (int i = 0; i < intervals.size(); i++) { result[i] = intervals.get(i); } ``` 上述代码通过逐个复制引用的方式将 `List<int[]>` 转换为 `int[][]`,避免了类型不匹配的问题[^2]。 ### 示例代码 以下是一个完整的区间合并示例,包含将 `List<int[]>` 正确转换为 `int[][]` 的逻辑: ```java import java.util.*; public class IntervalMerger { public static int[][] mergeIntervals(List<int[]> intervals) { if (intervals == null || intervals.isEmpty()) { return new int[0][]; } // 按照起始时间排序 intervals.sort(Comparator.comparingInt(a -> a[0])); List<int[]> merged = new ArrayList<>(); int[] current = intervals.get(0); for (int i = 1; i < intervals.size(); i++) { int[] next = intervals.get(i); if (current[1] >= next[0]) { // 合并区间 current[1] = Math.max(current[1], next[1]); } else { merged.add(current); current = next; } } merged.add(current); // 正确转换为 int[][] int[][] result = new int[merged.size()][]; for (int i = 0; i < merged.size(); i++) { result[i] = merged.get(i); } return result; } public static void main(String[] args) { List<int[]> intervals = Arrays.asList( new int[]{1, 3}, new int[]{2, 6}, new int[]{8, 10}, new int[]{15, 18} ); int[][] merged = mergeIntervals(intervals); for (int[] interval : merged) { System.out.println(Arrays.toString(interval)); } } } ``` 该方法确保了类型安全,并避免了 `ArrayStoreException`。 ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值