通用数组复制的问题

发布于 2024-10-24 18:46:57 字数 2797 浏览 0 评论 0原文

目标


我正在创建一个 Java 类,它将增强数组的可用性,例如 addremovecontains 方法。我认为最好的解决方案是创建一个具有类型参数 T 的类(称为 ArrayPP)。这样,用户就可以像与相同类型的数组进行交互一样轻松地与 ArrayPP 对象进行交互。

问题


我很快发现像 add 这样的方法将需要创建一个单独的数组,并最终将目标数组 tT 数组更改为将 code> 转换为 Object 数组。正如您可能猜到的那样,这完全破坏了可用性,当我尝试执行类似

File[] f = new File[0];
ArrayPP<File> appF = new ArrayPP(f);
appF.add(saveFile);
f = appF.toArray();

程序抛出的操作

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.io.File;

时,因为 add 方法必须将数组更改为 Object 数组s,因为 Java 编译器不允许您创建通用数组 (T[] t = new T[0]; 很糟糕,但是 T[] t = (T[] ) new Object[0]; 没问题)。我从逐行调试中知道,上面的代码将数组 t 保留在本例中,作为 File 的数组,直到 的第 4 行>add 方法被调用。 有没有人有一个解决方案可以使数组t保持为T数组而不是Object数组?< /strong>

示例代码


下面是我的课程的一个非常淡化的版本。

public class ArrayPP<T>
{
  T[] t;

  /**
   * Creates a new Array++ to manage the given array.
   * <h3>Analogy:</h3>
   * <tt>ArrayPP&lt;String&gt; s = new ArrayPP(args);</tt><br/>
   * is analogous to<br/>
   * <tt>String s[] = args;</tt>
   * @param array The array to be managed
   */
  public ArrayPP(T[] array)
  {
    t = array;
  }

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

  /**
   * Returns the array at the core of this wrapper
   * @return the array at the core of this wrapper
   */
  public T[] toArray()
  {
    return t;
  }
}

可能的解决方案?


在查看了有关泛型数组的其他问题后,我想我有一个解决方案:

而不是

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

这会起作用吗?

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP<T> add(T val)
  {
    t = java.util.Arrays.copyOf(t, t.length + 1);
    t[t.length - 1] = val;
    return this;
  }

Goal


I am making a Java class that will give enhanced usability to arrays, such as add, remove, and contains methods. I figured the best solution is to make a class (called ArrayPP) that has a type parameter T. This way, the user can interact with the ArrayPP object as easily as they can with an array of the same type.

Problem


I quickly found that such methods as add will require the creation of a separate array, and end up changing the target array t from an array of Ts into an array of Objects. As you may guess, this totally destroys the usability, and when I try to do something like

File[] f = new File[0];
ArrayPP<File> appF = new ArrayPP(f);
appF.add(saveFile);
f = appF.toArray();

the program throws

Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.io.File;

because the add method has to change the array into an array of Objects, as the Java compiler won't let you make a generic array (T[] t = new T[0]; is bad, but T[] t = (T[]) new Object[0]; is okay). I know from line-by-line debugging that the above code keeps the array t, in this case, as a n array of Files UNTIL the 4th line of the add method is called. Does anyone have a solution that will keep the array t being an array of Ts and not an array of Objects?

Sample Code


Below is a VERY watered-down version of my class.

public class ArrayPP<T>
{
  T[] t;

  /**
   * Creates a new Array++ to manage the given array.
   * <h3>Analogy:</h3>
   * <tt>ArrayPP<String> s = new ArrayPP(args);</tt><br/>
   * is analogous to<br/>
   * <tt>String s[] = args;</tt>
   * @param array The array to be managed
   */
  public ArrayPP(T[] array)
  {
    t = array;
  }

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

  /**
   * Returns the array at the core of this wrapper
   * @return the array at the core of this wrapper
   */
  public T[] toArray()
  {
    return t;
  }
}

Possible Solution?


After looking at other questions about generic arrays, I think I have a solution:

Instead of

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
    T[] temp = (T[]) new Object[t.length + 1];
    System.arraycopy(t, 0, temp, 0, t.length);
    temp[temp.length - 1] = val;
    t = (T[])temp;
    return this;
  }

will this work?

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP<T> add(T val)
  {
    t = java.util.Arrays.copyOf(t, t.length + 1);
    t[t.length - 1] = val;
    return this;
  }

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

罪#恶を代价 2024-10-31 18:46:57

原则上,您无法轻松创建泛型类型(或类型变量)的数组。

如果您有一个类对象,则可以使用反射,或者如果您有一个示例数组,则可以使用 java.util.Arrays 类中的方法来创建(更长/更短)副本。但无论如何它都不优雅。

ArrayList 类在内部简单地使用 Object[] 来存储其元素,并且仅在 get/set/add/toArray 上进行转换。
你的类在哪些方面比 ArrayList 做得更好?


编辑:

我建议要么简单地委托给 ArraysList,要么像 ArrayList 那样进行实现,在内部使用 Object[] ,并在必要时在输出上进行转换。

如果你真的想在内部拥有一个正确类型的数组,这是可能的 - 但正如我所说,它会变得很难看。

add 方法仍然是最简单的情况:

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
     T[] temp = Arrays.copyOf(t, t.length+1);
     temp[t.length] = val;
     t = temp;
     return this;
  }

当您想在中间添加或删除时,您必须将其与 arraycopy 结合起来。

In principle you can't easily create arrays of a generic type (or type variable).

If you have a class object, you can use reflection, or if you have an example array, the methods in the java.util.Arrays class to create a (longer/shorter) copy. But it is not elegant either way.

The ArrayList class internally simply uses an Object[] to store its elements, and converts only on get/set/add/toArray.
What would your class do better than ArrayList?


Edit:

I would recommend either simply delegate to an ArraysList, or do the implementation like ArrayList does, using an Object[] internally, and converting on output where necessary.

If you really want to have an array of the right type internally, it is possible - but it gets ugly, as I said.

The add method is still the easiest case:

  /**
   * Appends a value to the end of the array
   * @param val the value to be appended
   * @return the resulting array.
   */
  public ArrayPP add(T val)
  {
     T[] temp = Arrays.copyOf(t, t.length+1);
     temp[t.length] = val;
     t = temp;
     return this;
  }

When you want to add in the middle or remove, you'll have to combine this with your arraycopy.

枯叶蝶 2024-10-31 18:46:57

是否有某种原因导致内置 List 类无法满足您的需求?如:

String[] theArray = {"a", "b", "c"};
List<String> theList = Arrays.asList(theArray);

Is there some reason the built-it List<T> class(es) can't do what you need? As in:

String[] theArray = {"a", "b", "c"};
List<String> theList = Arrays.asList(theArray);
标点 2024-10-31 18:46:57
public ArrayPP(T[] array)
    componentClass = array.getClass().getComponentClass();

T[] newArray(int length)
    return Array.newInstance(componentClass, length)
public ArrayPP(T[] array)
    componentClass = array.getClass().getComponentClass();

T[] newArray(int length)
    return Array.newInstance(componentClass, length)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文