Java有没有办法初始化类型安全的通用数组?

时间:2013-02-11 20:13:14

标签: java generics

我有以下代码

public class Container<T> {
    private T element;
    private T[] tarray;

    public T getElement() {
        return element;
    }

    public void setElement(T element) {
        this.element = element;
    }

    public void add(T element) {
        tarray[0] = element;
    }

    public void CreateArray(int size) {
        //Can this be cleaned up better?
        tarray = (T[]) new Object[size];
    }

    public T get() {
        return tarray[0];
    }

    public Container(T someElement) {
        this.element = someElement;
    }

    public Container() {
    }

    public static void main(String[] args) {
        Container<String> myContaier1 = new Container<String>();
        myContaier1.setElement("Hello");
        myContaier1.CreateArray(1);
        myContaier1.add("GoodBye");
        System.out.println(myContaier1.get());
    }
}

是否无法初始化类型安全通用数组?

5 个答案:

答案 0 :(得分:6)

除非您以实际T对象的形式提供具体化的Class<T>,否则无法表示T的特定值。这是因为数组类型,而通用类型不是。

答案 1 :(得分:1)

这里有两个问题:

首先,数组的实际类型始终为Object[]。您将其投放到T[],但这只是因为T[]删除到Object[]。如果您的班级定义例如<T extends Number>,那么(T[])new Object[]将会失败ClassCastException

你可以通过将Class<T>传递给集合的构造函数并将其保存在字段中来解决这个问题:

private Class<T> componentClass;
...
tarray = (T[]) Array.newInstance(componentClass, size);

现在tarray的实际内存中类型为T[],但您仍然会收到未经检查的强制转换错误。即使你有组件类,据我所知,对于数组实例的检查强制转换没有等效的Class.cast()

答案 2 :(得分:-1)

您可以执行private T[] tarray;,但无法将其分配给(T[]) new Object[size];。 Object数组如何与任何其他类的数组相同。 编译后T甚至不存在。 它被称为类型擦除。例如,如果你这样做

List<Person> persons = new ArrayList<Person>();

编译后变为List persons = new ArrayList()

答案 3 :(得分:-1)

类似于询问“有没有办法初始化通用对象:new T()?”

当然这是不可能的,因为编译器不知道它的类型是什么。

数组是相同的,它的类型依赖于它的元素。如果其元素的类型未知,则其类型本身是未知的。

那些可以采用ListSetMap等通用类型的类是不同的。它们有自己的类作为类型,它们是动态的,因此您可以初始化类似new ArrayList<T>()


你可以试试这个:

public class Test {
    public static void main (String args[]) {
        int[] i = new int[3];
        short[] s = new short[4];
    ArrayList<String> a = new ArrayList<String>();

        System.out.println(i.getClass().getName());
        System.out.println(s.getClass().getName());
        System.out.println(args.getClass().getName());
        System.out.println(a.getClass().getName());
    }
}

您将看到元素的类型已经与数组结合,但未与ArrayList结合使用。

答案 4 :(得分:-1)

有一种方法可以在JVM上执行此操作,但要在Java中执行此类操作需要编写大量的样板代码。在Scala中,您可以使用清单来绕过类型擦除,并且可以在不进行转换的情况下实例化通用数组。

一个例子:

class Container[T : Manifest]() { 
  def createArray(size:Int) = Array.ofDim[T](size) 
}

scala> val f = new Container[String]
f: Container[String] = Container@12f3aa66

scala> f.createArray(5)
res7: Array[String] = Array(null, null, null, null, null)

Scala代码编译为与Java相同的字节码类文件(暗示如果你跳过足够的箍并且可能编写自己的清单,这在Java中应该是可能的)。 Scala类可以导入到Java项目中......虽然我不确定用Java实例化这样的类有多难。

如果您经常发现自己希望能够处理更复杂的类型情况,请查看Scala,您可能会喜欢它。