2

我有以下代码

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());
    }
}

有没有办法初始化一个类型安全的泛型数组?

4

5 回答 5

6

除非您TClass<T>表示T. 这是因为数组类型具体化了,而通用类型没有。

于 2013-02-11T20:15:03.277 回答
1

这里有两个问题:

首先,数组的实际类型始终是Object[]. 您将其投射到T[],但这仅适用T[]于擦除到Object[]。例如,如果您的类定义说 ,<T extends Number>那么(T[])new Object[]将失败并带有ClassCastException

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

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

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

于 2013-02-11T20:27:52.387 回答
-1

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

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

List persons = new ArrayList()编译后就变成了。

于 2013-02-11T20:17:35.773 回答
-1

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

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

Array 也是一样,它的类型依赖于它的元素。如果其元素的类型未知,则其自身的类型未知。

那些可以采用 , , 等泛型类型的类ListSet不同Map的。它们有自己的类作为类型并且它们是动态的,所以你可以初始化一个像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 组合。

于 2013-02-12T17:36:08.067 回答
-1

在 JVM 上可以做到这一点,但是在 Java 中做这样的事情需要编写大量的样板代码。在 Scala 中,您可以使用 Manifest 绕过类型擦除,并且可以在不强制转换的情况下实例化泛型数组。

一个例子:

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,您可能会喜欢它。

于 2013-12-19T21:06:01.370 回答