通用类型& toArrayMethod

时间:2014-11-04 19:02:19

标签: java generics types casting

我有一个类MyStack<T>,它定义了以下

public T[] toArray(){
  int s=size();
  @SuppressWarnings("unchecked")
  T[] result=(T[])new Object[s];
  Node n=first;
  for (int i=0; i<s; i++){
     result[i]=n.data;
     n=n.next;
  }
  return result;
}

由于这会返回一个类型为T的数组,我认为如果我声明了这个实例:MyStack<String> s=new MyStack<>,则以下内容完全有效:String[] test=s.toArray()。我认为这是因为s类型为StringtoArray应返回String类型的数组,因为String基本上已被替换为T {1}}在这个类中(我知道这个特定的实例化)。如果我执行此操作,唯一的方法是无错误运行:Object[] test=s.toArray()

为什么会这样?

2 个答案:

答案 0 :(得分:2)

总之,键入擦除。摘自Java网站:

  

如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。因此,生成的字节码只包含普通的类,接口和方法。

这意味着,在编译代码时,MyStack<String>会被编译为MyStack<Object>。这是为了确保泛型不会因需要创建新类而产生开销。这对你有什么用?以及..

MyStack<String> s = new MyStack<>();

转换为..

MyStack<Object> s = new MyStack<>();

现在,这意味着当您调用toArray方法时,唯一可以 guarenteed 的类型是Object类型。编译器无法确定它返回的所有内容都是String类型,因此由于Java中的强类型,它不会让您将其视为String。那么,剩下的唯一变量类型是什么?

Object[] array = s.toArray();

额外阅读

答案 1 :(得分:1)

好吧,等一下。假设您的假设是正确的,String替换了每个T

以下演员会有效吗?

String[] result = (String[])new Object[s];
不,它不会。我们可以确定new Object[]不是String[]

现在有时你会看到像(T[])new Object[n]这样的东西,但它只能起作用,因为强制转换实际上变成了erased在泛型类中。 (这是一种欺骗性的习语。)

当编译类时,实际发生的是T的引用被替换为其上限(可能是Object,除非你有类似<T extends ...>的东西):

public Object[] toArray(){
  int s=size();
  Object[] result=new Object[s];
  Node n=first;
  for (int i=0; i<s; i++){
     result[i]=n.data;
     n=n.next;
  }
  return result;
}

演员表被移动到呼叫站点:

MyStack stack = new MyStack();
String[] arr = (String[])stack.toArray();

所以实际上,当在类中删除了强制类型转换时,一旦将值返回到类的外部(其中抛出ClassCastException),就会发生强制转换。

无法一般地实例化数组(和一般对象)是Collections框架定义其toArray方法以将返回数组作为参数的原因。这个的简单版本如下:

public T[] toArray(T[] inArray){
    int s = size();

    Node n = first;
    for (int i = 0; i < s; i++){
        inArray[i] = n.data;
        n = n.next;
    }

    return inArray;
}

有关如何一般创建数组的一些想法,您可能会看到'How to create a generic array in Java?';但是你需要调用者将一些参数传递给方法。