标题:ArrayList使用toArray()构造数组时的问题
关键字:toArray 构造数组
作者:jrq
摘要:解决使用ArrayList.toArray()构造数组时的问题。做备忘。
本文链接: http://blog.csdn.net/jrq/archive/2005/10/27/517428.aspx
正文:
1. 为了方面按列作外循环,想把ArrayList构造成一个二维数组,如下:
......
ArrayList result=GetResult();
int n=result.size();
String[][] myArray=new String[n][]; //定义二维数组
for (int i=0;i<n;i++) //构造二维数组
{
ArrayList tempArray= (ArrayList)result.get(i);
myArray[i]=(String[])tempArray.toArray();
}
......
程序可以编译通过。
但在运行到myArray[i]=(String[])tempArray.toArray()时,出现java.lang.ClassCastException的错误,很奇怪。
花了一晚上时间,查了N多资料,总算搞定了。现把问题记录下来,以备参考。
2. 此事从头说起。
ArrayList类扩展AbstractList并执行List接口。ArrayList支持可随需要而增长的动态数组。
ArrayList有如下的构造函数:
ArrayList( )
ArrayList(Collection c)
ArrayList(int capacity)
如果调用new ArrayList()构造时,其默认的capacity(初始容量)为10。
参见ArrayList源码,其中是这样定义的:
public ArrayList() {
this(10);
}
默认初始化内部数组大小为10。为什么是10?不知道。可能SUN觉得这样比较爽吧。
程序编译后执行ArrayList.toArray(),把ArrayList转化为数组时,该数组大小仍为capacity(为10)。
当装入的数据和capacity值不等时(小于capacity),比如只装入了5个数据,数组中后面的(capacity - size)个对象将置为null,此时当数组强制类型转换时,容易出现一些问题,如java.lang.ClassCastException异常等。
解决办法是:在用ArrayList转化为数组装数据后,使用trimToSize()重新设置数组的真实大小。
3. 本例修改后的代码修如下,可顺利运行:
for (int i=0;i<n;i++) //构造二维数组
{
ArrayList tempArray= (ArrayList)result.get(i);
myArray[i]=(String[])tempArray.toArray(new String[0]); //注意此处的写法
}
看看下面这些也许就明白了--
ArrayList.toArray()之一:
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对象);要是不够大,就申请一个跟参数同样类型的数组,把值放进去,然后返回。
4. 网上的资料一:
public String[] getPlatformIDList()
{
Vector result = new Vector();
try
{
Statement stmt = conn.createStatement();
String sql = "SELECT PlatformID FROM Platform";
rs = stmt.executeQuery(sql);
while(rs.next())
{
result.add(rs.getString(1));
}
if (result.size() > 0)
{
String[] str = (String[]) result.toArray(); // 出现ClassCastException
return str;
}
else
return null;
}
catch(Exception e)
{
System.err.println(e);
return null;
}
finally
{
try
{
rs.close();
conn.close();
}
catch(Exception e2)
{}
}
}
程序运行后,发现不能将Vector类经过toArray()方法得到的Object[]直接转换成String[]。
找到用另一个带有参数的 toArray(T[] a)方法才可以。
将该语句改为:
String[] str = (String[]) result.toArray(new String[1]);即告诉Vector,我要得到的数组的类型。
回想一下,应该是java中的强制类型转换只是针对单个对象的,想要偷懒,将整个数组转换成另外一种类型的数组是不行的。
5. 网上的资料二:
正确使用List.toArray()--
在程序中,往往得到一个List,程序要求对应赋值给一个array,可以这样写程序:
Long [] l = new Long[list.size()];
for(int i=0;i<list.size();i++)
l[i] = (Long) list.get(i);
要写这些code,似乎比较繁琐,其实List提供了toArray()的方法。
但是要使用不好,就会有ClassCastExceptiony异常。究竟这个是如何产生的,且看代码:
List list = new ArrayList();
list.add(new Long(1));list.add(new Long(2));
list.add(new Long(3));list.add(new Long(4));
Long[] l = (Long[])list.toArray();
for(int i=0; i<l.length; i++)
System.out.println(l[i].longValue());
红色代码会抛java.lang.ClassCastException。
当然,为了读出值来,你可以这样code:
Object [] a = list.toArray();
for(int i=0;i<a.length;i++)
System.out.println(((Long)a[i]).longValue());
但是让数组丢失了类型信息,这个不是我们想要得。
toArray()正确使用方式如下:
1)Long[] l = new Long[<total size>];
list.toArray(l);
2) Long[] l = (Long []) list.toArray(new Long[0]);
3) Long [] a = new Long[<total size>];
Long [] l = (Long []) list.toArray(a);
6. 总结补充:
java sdk doc 上讲:
public Object[] toArray(Object[] a)
a--the array into which the elements of this list are to be stored, if it is big enough; otherwise, a new array of the same runtime type is allocated for this purpose.
如果这个数组a足够大,就会把数据全放进去,返回的数组也是指向这个数组,(数组多余的空间存储的是null对象);要是不够大,就申请一个跟参数同样类型的数组,把值放进去,然后返回。
需要注意的是:你要是传入的参数为9个大小,而list里面有5个object,那么其他的四个很可能是null , 使用的时候要特别注意。
7. 完毕。
J.R.Q.
2005.10.27凌晨于广州
分享到:
相关推荐
在使用 ArrayList 时,需要注意线程同步的问题,如果使用非线程同步的实例,那么在多线程访问的时候,需要自己手动调用 lock 来保持线程同步。同时,ArrayList.Synchronized 方法可以返回一个线程同步的 ArrayList ...
### Java中数组列表ArrayList的使用详解 #### 一、ArrayList简介 `ArrayList`是Java集合框架中的一个重要组成部分,属于`List`接口的一种实现。它提供了一种动态调整大小的数组,能够有效地解决传统数组大小固定...
在Android开发中,数据...而在数组转换为ArrayList时,优先考虑Arrays.asList(),若需要可修改的ArrayList,再进一步构造新的ArrayList。理解这些转换方法能帮助开发者更加灵活地处理数据,提高代码的可读性和维护性。
下面将详细讨论ArrayList的使用、重要方法和属性,以及与数组之间的转换。 1. **ArrayList的基本概念** - ArrayList是一种动态数组,它允许我们在运行时动态地添加或删除元素,而无需预先知道数组的精确大小。 - ...
2. `toArray(T[] array)`:将ArrayList转换为指定类型的数组。 九、ArrayList的线程安全性 ArrayList不是线程安全的,这意味着在多线程环境下,对ArrayList的操作需要额外的同步措施,如使用`Collections....
- ArrayList 默认不是线程安全的,多线程环境下使用时需要手动同步,或者使用 `Collections.synchronizedList(ArrayList list)` 创建线程安全的 ArrayList。 6. **性能考虑** - ArrayList 的插入和删除操作在中间...
ArrayList是Java中一种常见的动态数组实现,它是List接口的一个实现类,主要特点是可以在运行时自动调整其容量以适应元素数量的变化。ArrayList的核心概念基于数组,但比数组更加灵活,因为它支持动态增长和缩小,...
- `ArrayList`可以通过构造函数直接从数组创建,反之亦然,使用`toArray()`方法。 11. **数组的长度**: - 使用`length`属性获取数组的元素个数,如`int len = array.length`。 12. **数组与字符串的交互**: -...
同时,你可以通过`Add`方法连续添加元素,或者通过`ToArray`方法将ArrayList转换为特定类型的数组: ```java for (int i = 0; i ; i++) list.add(i + 20); Int32[] values = (Int32[])list.toArray(new Int32[0]);...
- ArrayList与数组之间的转换,可以使用`ToArray`方法或`CopyTo`方法。 5. ArrayList与其他数据结构的区别 - 相比数组,ArrayList在添加和删除元素时更灵活,但随机访问效率略低于数组。 - ArrayList不保证元素...
在使用`ArrayList`时,有一些性能上的考量: - 尽可能提前指定初始容量以避免不必要的扩容操作。 - 如果`ArrayList`包含大量不同类型的对象,最好使用泛型`List<T>`,因为它提供了更好的类型安全性和性能。 - ...
### C# 中 ArrayList 的使用详解 #### 一、概述 在C#中,`ArrayList`是一种非常实用的数据结构,它可以被视为动态数组的...通过理解其构造函数、属性和常用方法,开发人员可以有效地利用`ArrayList`解决各种实际问题。
11. **ToArray方法**:将ArrayList转换为常规数组。重写时,需要创建一个新的数组,并将ArrayList的所有元素复制到新数组中。 12. **Clone方法**:创建ArrayList的浅拷贝。这意味着新实例引用相同的元素,但不是新...
* `toArray()`: 按适当顺序返回包含 ArrayList 中所有元素的数组。 实例 以下是一个使用 ArrayList 类的实例代码: ```java import java.util.ArrayList; public class List { public static void main(String[]...
ArrayList 是线程不安全的集合,这意味着在多线程环境下操作 ArrayList 时,不会自动同步对它的访问,使用时需要自行保证线程安全。其底层数据结构是数组,因此每个 ArrayList 实例都具有一个容量,用于表示底层数组...
在Java编程中,集合(比如ArrayList)和数组是两种常见的数据结构,它们各自有各自的特性和使用场景。这里我们将详细探讨如何将集合(以ArrayList为例)与数组进行互相转换,并理解其中的关键点。 首先,集合(List...
- **构造器**:如上所述,有三种构造方法,用于初始化ArrayList。 - **IsSynchronized属性**:表示ArrayList是否线程安全。若不使用线程同步,需手动使用`lock`关键字确保线程安全。 - **Synchronized方法**:...
为了提高内存效率,在不使用数组后或者数组不再需要那么大的容量时,可以使用`TrimToSize`方法来减小`ArrayList`的容量,使之与当前元素数量相匹配。 #### 六、数组转换 由于`ArrayList`内部存储的是`object`类型...