`
xfei6868
  • 浏览: 69799 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Converting a Collection<T> to an array

阅读更多
   原文: http://www.javablogging.com/converting-a-collection-to-an-array/

   如果你已经使用了java5的Collections有可能被Collection<T>输出数组类型为T的问题难倒。在Collection Interface中有方法 toArray() 返回 Object[] 类型。但是,如果java5的Collection使用泛型,难倒不应该得到一个array T[] 使用在我们的Collection<T>的声明中?当然有一个方法 T[] toArray(T[] a)。但是哪来的这个奇怪的“T[] a”?为什么不是一个简单的没有奇怪参数的方法 T[] toArray(T[] a)?看起来在java5中实现这样一个方法不应该有大的问题,但是事实上不肯能做到在java5,我们在下面说明为什么。

    我们从尝试自己实现这样一个方法开始,例如,我们可以通过继承 ArrayList 类来实现方法T[] toArrayT()。为了简单我们通过强制转换 Object[] toArray() 方法为T[]来实现:



import java.util.*;

/**
 * Implementation of the List interface with "T[] toArrayT()" method.
 * In a normal situation you should never extend ArrayList like this !
 * We are doing it here only for the sake of simplicity.
 * @param <T> Type of stored data
 */
class HasToArrayT<T> extends ArrayList<T> {
    public T[] toArrayT() {
        return (T[]) toArray();
    }
}

public class Main {
    public static void main(String[] args) {
        // We create an instance of our class and add an Integer
        HasToArrayT<Integer> list = new HasToArrayT<Integer>();
        list.add(new Integer(4));

        // We have no problems using the Object[] toArray method
        Object[] array = list.toArray();
        System.out.println(array[0]);

        // Here we try to use our new method... but fail on runtime
        Integer[] arrayT = list.toArrayT(); // Exception is thrown :
        // "Ljava.lang.Object; cannot be cast to [Ljava.lang.Integer"
        System.out.println(arrayT[0]);
    }
}


   如果你编译这段代码,当我们尝试使用这个新方法它会抛出一个 exception。但是为什么呢?但是为什么?难倒是我们做的不对?存储是Integers 和 toArray 方法返回的Objects数组,所以这才是问题所在。

    Java 编译器 给我们一个提示来理解我们的错误。通过编译你将看到第11行的warning,说一些什么“Type Safety”。 Unchecked cast 从 Object[] 到 T[],跟随这个问题检查这个 array 从方法 toArrayT() 返回的真正类型是 Integer[],把下面的代码放在main()中代码
Integer[] arrayT = list.toArrayT()
之前:

    System.out.println("toArrayT() returns Integer[] : "
    + (list.toArrayT() instanceof Integer[]));


    当你运行这个程序,你应该得到一个"false",这意味着toArrayT()返回的并不是Integer[],为什么呢?也许许多人知道答案,这就是Type Erasure。基本上,编译器在编译过程中会去除一切关于泛型的任何类型。当程序运行时,所有的 T 在 HasToArrayT类 中的表象并不是一个简单的对象。这意味着,方法toArrayT 并没有转换成Integer[],即使泛型中定义的为Integer。其实这里还有第二个问题,来自java处理数组转换的方式。现在我们只想集中在第一个问题--泛型的使用。

    所以,如果 T 代表 Integer 却会在运行期擦除,有没有什么方法返回真正的array of type Integer[]?当然可以而且是已经存在的,方法 T[] toArray(T[] a)在Collections框架就是这个作用。但是代价就是添加了一个自己创建的参数实例。怎么使用它呢?让我们看看它们是怎么实现的?例如,ArrayList的实现:

public <T> T[] toArray(T[] a) {
    if (a.length < size)
        // Make a new array of a's runtime type, but my contents:
        return (T[]) Arrays.copyOf(elementData, size, a.getClass());
    System.arraycopy(elementData, 0, a, 0, size);
    if (a.length > size)
        a[size] = null;
    return a;
}


    按照javadoc中的这个方法的解释,如果这个制定的数组 a 有足够大的空间满足elements放在这个数组中,如果没有足够空间将会创建一个新的数组。我们看到实现中它通过Arrays.copyOf 方法创建一个新的数组,通过 a.getClass() 来指定要创建数组的类型。这就是为什么它需要一个参数--为了知道要创建数组的类型。然后你也许会说通过 T.class 替代 a.getClass()会不会显得更简单?不!因为type erasure,T不是一个我们指定的一个类型。而且我们如果我们使用T.class会得到一个编译器错误!也许你想到一个创建新数组的简单方法 -- new T[], 但是由于同样的原因仍然不可能。

    直接的说,为了返回一个真正指定类型的array of T,必须为函数 toArray 提供相应的类型。现在并没有其他的方式可以提供函数中创建的数组类型,由于泛型 T 在Collection运行期创建时被取消。

    另外一个途径就是通过传递一个 Class<T[]> 输入参数实现这个函数,这种方式通过创建一个新的数组T[]替代 toArray(a) 中的 a, 我们可以用 .class 域 -- toArrayT(TYPE[].class)

public T[] toArrayT(Class<T[]> c) {
    return (T[]) Arrays.copyOf(toArray(), size(), c);
}


    它仍然需要一个参数,但是这有两个好处在T[] toArray(T[] a)函数。首先,它不需要另外常见一个数组而是直接使用传递来的实例。第二,它简单,当然它的确定也是有一个传入参数。

    总之,没有完美的解决办法,最好的解决办法是不使用数组。数组代码很难控制并且导致人去犯错并出现在运行的时候。如果你经常使用collections 并且熟悉,你想不能逃避关于注意 toArray 方法。
   
分享到:
评论

相关推荐

    VB编程资源大全(英文源码 其它)

    array.zip&lt;br&gt;A simple program that shows how a two-dimensional array works within a VB program.&lt;END&gt;&lt;br&gt;70,Bubblesort.zip&lt;br&gt;A simple Bubble Sort code that shows how the program works within a VB ...

    CImg Reference

    - Each node in the list contains a pointer to the `CImg&lt;T&gt;` object and other necessary information for managing the list. ##### 3. `CImgDisplay` **Structure Overview:** - `CImgDisplay` is used for ...

    Python Cookbook, 2nd Edition

    Adding an Entry to a Dictionary Recipe 4.11. Building a Dictionary Without Excessive Quoting Recipe 4.12. Building a Dict from a List of Alternating Keys and Values Recipe 4.13. Extracting a ...

    GObject Reference Manual

    Value arrays - A container structure to maintain an array of generic values III. Tools Reference glib-mkenums - C language enum description generation utility glib-genmarshal - C code marshaller ...

    php.ini-development

    E_ALL & ~E_NOTICE), a quoted string ("bar"), or a reference to a ; previously set variable or directive (e.g. ${foo}) ; Expressions in the INI file are limited to bitwise operators and parentheses: ...

    SCJP6 Sun Certificated Programmer for Java 6 Study Guide (Exam 310-065) 英文原版

    - **Type Casting**: Converting one type to another, including upcasting and downcasting. - **Array Assignments**: Creating and initializing arrays, including multi-dimensional arrays. #### 4. ...

    Professional C# 3rd Edition

    Converting XML to ADO.NET Data 820 Reading and Writing a DiffGram 822 Serializing Objects in XML 825 Serialization without Source Code Access 833 Summary 836 Chapter 24: Working with Active Directory ...

    python3.6.5参考手册 chm

    PEP 372: Adding an Ordered Dictionary to collections PEP 378: Format Specifier for Thousands Separator PEP 389: The argparse Module for Parsing Command Lines PEP 391: Dictionary-Based Configuration...

    深入理解计算机系统(英文版)

    1.4.1 HardwareOrganization of aSystem . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.4.2 Running the helloProgram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8 1.5 CachesMatter ...

Global site tag (gtag.js) - Google Analytics