【问题标题】:What is the easiest alternative to a generic array in Java?Java中泛型数组的最简单替代方法是什么?
【发布时间】:2010-09-27 21:17:17
【问题描述】:

假设我有这个:

class test<T>
{
    private T[] elements;
    private int size;
    public test(int size)
    {
        this.size = size;
        elements = new T[this.size];
    }
}

这似乎是不可能的,因为一旦编译器试图替换泛型代码或其他东西,它就不知道要调用什么构造函数。我想知道的是,我该怎么做呢?我想这是可能的,因为它在 C++ 中很容易做到。

编辑:抱歉,我忘记了元素声明中的 []。

【问题讨论】:

    标签: java arrays generics


    【解决方案1】:

    我可能错了,但你的声明似乎很奇怪,你不应该有吗:

    private T[] elements;
    

    【讨论】:

      【解决方案2】:

      问题在于,由于泛型类型参数T 被编译器转换为Object(称为类型擦除),因此您实际上创建了一个Object 数组。您可以为函数提供Class&lt;T&gt;

      class test<T>
      {
          private T[] elements;
          private int size;
          public test(Class<T> type, int size)
          {
              this.size = size;
              elements = (T[]) Array. newInstance(type, size);
          }
      }
      

      你会在这里找到更好的解释:Angelika Langer - Can I create an array whose component type is a type parameter?

      【讨论】:

        【解决方案3】:

        通用数组的最简单替代方法是使用列表。

        【讨论】:

        • 我同意 - 出于多种原因,列表通常是更好的选择。事实上,有些人会建议将数组视为 Java 5+ 中已弃用的语言部分。我不是说我是他们中的一员……但你会发现这种观点。
        • 数组对原始类型仍然有效。但对于引用类型,它几乎一直都是不恰当的优化。
        【解决方案4】:

        有两种解决方案不需要传入类对象。在这两种情况下,我都假设因为它是一个私有变量,所以你是唯一将东西放入其中的人,而外界看不到它。

        一种是只使用一个普通的对象数组Object[]。缺点是您将失去泛型的好处,并且您将不得不从它那里抛出一些东西,这使得代码更加丑陋。但既然你是唯一一个把东西放进去的人,那么演员应该总是安全的。外界不需要知道发生了什么。

        其他选项有点像黑客。您创建一个Object[],然后将其“转换”为T[]。从技术上讲这是非法的,因为Object[]T[] 是不同的运行时类型,前者不能转换为后者。但是只要您不将数组传递出类(例如返回它或其他),那么它不会引起任何问题,因为T[] 无论如何都会被擦除为Object[],实际上没有演员表执行。然后,您可以在您的类中获得泛型的好处,以便更轻松地编码,但您必须非常小心,不要将该数组传递给任何实际期望 T[] 的人,因为它不是。

        【讨论】:

          【解决方案5】:

          出于多种原因,我倾向于避免使用基本数组并尽可能使用ArrayLists(或类似的Lists)。最重要的两个是:

          1. 我不需要 bald 数组的语义。括号符号(即指针算术的简写)并没有让我的生活更轻松。

          2. 如果我使用列表,我会根据需要设置自己使用更复杂的支持并发的结构。例如,用CopyOnWriteArrayList 替换 ArrayList 非常容易。

          因此,使用通用 ArrayList 编写示例将如下所示:

          class test<T> {
              /** It's not strictly necessary to make this a List vs. an ArrayList
                  You decide what interface you really need to expose internally. */
              private List<T> elements;
              /** This parameter isn't necessary with a List.  You can always call the
                  size() method instead. */
              private int size;
              public test(int size) {
                  this.size = size;
                  elements = new ArrayList<T>();
                  // Note that the next line isn't strictly necessary.
                  // An ArrayList can be dynamically resized without any real effort on your part.
                  elements.ensureCapacity(size); 
              }
          }
          

          【讨论】:

            【解决方案6】:

            size 字段确实显得多余。您可以只使用 elements.length 而不是 size。

            class Test<T> {
                private final T[] elements;
                public test(int size) {
                    elements = (T[]) new Object[size];
                }
            }
            

            或者您可以将 Test 类替换为 ArrayList。即完全放弃课程。

            【讨论】:

            • 这将引发异常,因为新数组不是 T[] 类型。
            • @pdeva:不,不会的;只要它留在类Test中,它就不会抛出任何异常,因为T[]的擦除是Object[];但你要小心不要让它离开课堂
            【解决方案7】:

            也看看这段代码:

            public static <T> T[] toArray(final List<T> obj) {
                if (obj == null || obj.isEmpty()) {
                    return null;
                }
                final T t = obj.get(0);
                final T[] res = (T[]) Array.newInstance(t.getClass(), obj.size());
                for (int i = 0; i < obj.size(); i++) {
                    res[i] = obj.get(i);
                }
                return res;
            }
            

            它将任何类型的对象列表转换为相同类型的数组。

            【讨论】:

              猜你喜欢
              • 2021-11-11
              相关资源
              最近更新 更多