2011-09-01 113 views
1

可能重复:
Java how to: Generic Array creation我们可以创建一个泛型类的数组吗?

我想创建一个包含10个元素堆栈,我试图与泛型做到这一点。 我开始创建类型T的Stack类,但是当我尝试实例化泛型类型的数组时,出现了编译错误。

public class Stack<T>{ 
    private T[] stk = new T[10]; 
} 

我在做什么错在这里?

+0

由于类型删除无法完成。请参阅http://stackoverflow.com/questions/2927391/whats-the-reason-i-cant-create-generic-array-types-in-java。 –

+0

我想你可以,检查这个: 看到这个链接:http://stackoverflow.com/questions/529085/java-how-to-generic-array-creation – sfrj

+0

这似乎是显示了Java问题之一每隔几天。 –

回答

3

你不能这样做。不是没有使用一些关于代码的hacky round,即使如此,你最终还是必须做一个unsafe,这完全破坏了首先尝试安全类型的全部理由。

这是因为Java有一些名为type erasure的东西,编译器会抛弃所有通用信息,而运行时不知道什么是T

这里是这样做的首选方式:

@SuppressWarnings("unchecked") 
static <T> T[] newArray(Class<T> type, int length) 
{ 
    return (T[]) java.lang.reflect.Array.newInstance(type, length); 
} 

在一个List<T>实施黑客调用toArray()天真的解决方案这不创建有关列表实例抛出。

有关此更多的讨论,参见

Here is an answer to a similar question about creating a type safe array at runtime

1

你不能创建一个通用型的阵中还有原因是这样的:

当一个泛型类型实例化时,编译器的技术叫做类型擦除转换的类型 - 一个过程,其中编译器中删除所有与类或参数类型有关的信息。 Type erasure使得使用泛型的Java应用程序能够保持与泛型之前创建的Java库和应用程序的二进制兼容性。例如,Box被转换为Box类型,它被称为原始类型 - 原始类型是不带任何类型参数的泛型类或接口名称。这意味着您无法找到泛型类在运行时使用的对象类型。下面的操作是不可能的:

public class MyClass<E> { 
    public static void myMethod(Object item) { 
     if (item instanceof E) { //Compiler error 
      ... 
     } 
     E item2 = new E();  //Compiler error 
     E[] iArray = new E[10]; //Compiler error 
     E obj = (E)new Object(); //Unchecked cast warning 
    } 
    } 

http://download.oracle.com/javase/tutorial/java/generics/erasure.html

使用泛型的原因是,你不想类型转换。

这就是说,这里有两个解决方案。

public class MyStack2<T> { 
Object[] myStack2; 

public MyStack2() { 
    myStack2 = new Object[10]; 
} 

public void push(T t) { 
    // do whatever you wanna do to push t, like myStack2[x] = t; 

} 

public T pop() { 
    // do whatever you wanna do to pop t like return (T)myStack2[0]; 
      // Here we typecasted, but we can be sure that myStack2 contains only T's 
      // because we garanteed it at the push method. 
} 

}

OR

您可以:

您可以根据您所提供访问阵列的方法使用对象的数组和garantee你只推和弹出T的使用数组以外的其他东西来存储您的堆栈。

public class MyStack<T> { 
    Stack<T> myStack; 

    public MyStack() { 
     myStack = new Stack<T>(); 
    } 

    public void push(T t) { 
     myStack.push(t); 
    } 

    public T pop() { 
     return myStack.pop(); 
    } 
} 

正如你所看到的,JAVA已经提供了Stack类,这样你就不必写了一个,但如果你真的想这样做,可能了解它是如何工作的,可以更换Stack类在这个例子中由一个List。如果你使用的是数组,你将可以使用与List相同的功能。

1

不起作用的原因是,当您在Java中编写类似String[]的类型时,这意味着对象在运行时知道其组件类型为String(或其子类)。泛型类型参数在运行时不可用,因此您不能这样做。我们希望有类似于Object[]<T>的东西,即“在运行时不知道其组件类型,但在编译时具有泛型类型检查的数组”,但这种东西在该语言中不存在。

但是,从代码看来,您打算在内部使用此数组,并且您并不在乎数组在运行时是否知道T;你只需要一个数组,句号。如果你不打算阵列传递出类的,那么有两种选择:

  1. 使用Object[]类型的变量,并创建new Object[10]。如果你想从方法中返回一个元素,这是一个未经检查的强制转换,这就需要你投到T

  2. 使用类型T[]的变量,并使用= (T[])new Object[10]进行赋值。现在人们会指出,子类型关系在技术上并不真实,但只要它属于课堂内部(在T范围内),这并不重要,因为T已被删除。所以使用这种方法时,您必须格外小心,不要传递或返回数组引用,因为您不会被警告它不安全。

这两种方法都是类型擦除后相同,这两种方法都会造成选中投警告,所以它的真的是你的个人喜好。第二种方法更方便(假设它是T[],并且没有演员就可以把它弄出来),而第一个更正式,更安全(第二个要求你勤奋不要传递出去)。

相关问题