【问题标题】:How to declare and instantiate a new Generic array?如何声明和实例化一个新的通用数组?
【发布时间】:2013-02-21 01:29:10
【问题描述】:

我正在复习我的数据结构技能。我在网上找到了一本很棒的免费书,名为Open Data Structures in Java.。通读后,我尝试使用提供的代码创建所有声明的数据结构,以便将它们灌输到我的记忆中。

我遇到了一个“错误”,我一辈子都想不通:在 ArrayStackresize() 方法中(第 2.1.2 节),有一行代码 - T[] b = newArray(Math.max(n*2,1));。这样做的重点是包含元素的数组既不会太小也不会太大。如果我使用这行代码,我会从 Eclipse 收到以下错误消息:

The method newArray(int) is undefined for the type ArrayStack<T>.

所以,我认为它一定是一个“错字”,意思是“新数组”。但是修复它会给我留下来自 Eclipse 的以下错误消息:

Type mismatch: cannot convert from Array to T[].

我不明白我错过了什么或做错了什么。 总结一下我的问题,如何声明和实例化一个新的泛型数组,尤其是在固定大小的情况下?

【问题讨论】:

    标签: java arrays generics data-structures generic-programming


    【解决方案1】:

    鉴于T的类,我们称它为klass...

    对于长度为n的一维数组:

    T[] arr = (T[]) Array.newInstance(klass, n)
    

    对于长度为n x m的二维数组:

    T[][] 2dArr = (T[][]) Array.newInstance(klass, n, m)
    

    上面实际上是两个不同的函数,一个接受int 参数,第二个接受int... 参数,您也可以将其作为数组传递。两者都返回一个Object,您需要对其进行未经检查的强制转换。

    如果你想要一个长度为n的锯齿状数组,第二维不确定,你必须得到T[]的类,我们称之为klass2,然后做

    T[][] 2dArr2 = (T[][]) Array.newInstance(klass2, n)
    

    这就是为什么您还需要将类型传递给collection.toArray(T[] arr),否则您会得到一个Object[] 用于普通的toArray() 方法,因为它不知道类型。

    【讨论】:

      【解决方案2】:

      你想要的是:

      void resize() {
          T[] b = new T[Math.max(n*2,1)];
          for (int i = 0; i < n; i++) {
              b[i] = a[i];
          }
          a = b;
      }
      

      但这不起作用,因为 T 在运行时实际上并不知道,而且它必须是。但是,这可以使用泛型安全的构造函数来编写。

      void resize() {
          T[] b = (T[]) Array.newInstance( a.getClass().getComponentType(),
                                           Math.max(n*2,1) );
          for (int i = 0; i < n; i++) {
              b[i] = a[i];
          }
          a = b;
      }
      

      看来作者的意思是在那个类中有一个方法,newArray:

      void T[] newArray(int size) {
          return (T[]) Array.newInstance( a.getClass().getComponentType(), size);
      }
      

      【讨论】:

      • 不,它不允许你为泛型这样做,它会给你这个错误消息:Cannot create a generic array of T
      • 好的,我明白了。 Samuel Edwin Ward 为您提供了解决类型擦除问题的答案。
      【解决方案3】:

      Java 并没有让这件事变得简单。由于type erasure,T 的类在运行时不可用(此时需要确定要创建的数组类型)。

      但是,由于您已经有一个数组 (a),您可以使用反射来创建该类型的新数组。

      它看起来像这样:

      import java.lang.reflect.Array;
      
      public class Test {
      
              public static void main(String args[]) throws Exception {
                      Object array[] = new Object[5];
      
                      array = resizeArray(array, 10);
      
                      for (Object o : array) {
                              System.out.println(o);
                      }
              }
      
              public static <T>
              T[] resizeArray(T[] a, int newSize) throws Exception {
                      T[] b = (T[]) Array.newInstance(a.getClass().getComponentType(),
                                                      newSize);
      
                      for (int i = 0; i < a.length; i++) {
                              b[i] = a[i];
                      }
      
                      return b;
              }
      }
      

      【讨论】:

      • 好的,所以书中的T[] b = newArray(Math.max(n*2,1)); 行只是作为我必须创建一个新数组的参考?它本身不是代码吗?所以我可能不得不使用java.lang.reflect.Array.newInstance() 来创建一个任意类型的数组。
      • @AndroidStudent,我想是的。我刚刚在我的答案中添加了示例代码。我可以看到这本书的作者不想在他的代码中加入这种怪物,因为它会分散手头的话题。
      • 公平地说,这本书的作者应该指出他的代码无效,或者只是使用了Object[]。似乎有点草率。
      • 也许他们应该使用一种对参数化类型有更好支持的语言......
      • @AndroidStudent 看来newArray()是一个方法调用。不过,我无法在您链接的文本中找到它的定义位置。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-09
      • 1970-01-01
      • 2014-01-26
      • 2011-08-11
      • 1970-01-01
      • 2015-12-23
      相关资源
      最近更新 更多