从通用类中返回一个数组

7
当我运行此代码时,因为将d隐式转换为double,所以出现了ClassCastException错误。然而,如果我将对d的引用更改为Object[],则它不能成为set函数的参数。如果我将set函数更改为接受Object[],那么一切都正常工作,但是如果有人在不是N类型的对象上调用set,则该类将在运行时失败。
我需要一个解决方案,可以“get()”旧数组(或其克隆),并且可以向新数组中“set()”数据。
public class Foo<N> {

    public static void main(String[] args) {
        Foo<Double> foo = new Foo<Double>();
        Double[] d = foo.get();

        // do stuff to d ...

        foo.set(d);
    }

    N[] data;

    public Foo() {
        data = (N[]) new Object[2];
    }

    public N[] get() {
        return (N[]) data;
    }

    public void set(N[] data) {
        this.data = data;
    }

}

1
可能是如何在Java中创建通用数组?的重复问题。 - Julien
这不是那个问题的重复。 - avisnacks
你可以使用这个链接 https://dev59.com/vXA75IYBdhLWcg3wPmZ8#3403976 来提取类型,并使用Array.newInstance来创建数组。 - AdamSkywalker
4个回答

1

这里有一个窍门。

class Foo<N> {

    // Deliberately no parameters.
    N[] myArray = makeArray();

    private N[] makeArray(N... ns) {
        return ns;
    }

    public N[] get() {
        return myArray;
    }
}

这看起来好像没有强制类型转换(这是一件好事),但实际上确实有转换,只不过是由 varargs系统完成的。


也许我没有清楚地表达问题,但在我的情况下,数组已经被实例化,我需要对其进行更改。因此,我需要从foo获取它并对其进行操作。然后重置它。我不能有一个在构造函数中实例化它的解决方案。 - avisnacks
2
@avisnacks:在你的例子中,你是在Foo构造函数中创建数组的。这不是应该的工作方式吗?你能否更新问题以使其更清晰? - Lii
@OldCurmudgeon:这样是行不通的。你总是会在myArray中得到一个Object数组。当初始化器调用makeArray时,没有留下N的痕迹,它已经被擦除了。泛型可变参数方法总是创建Object数组。根本无法创建泛型类型的数组。例如,在Java教程中已经描述了这一点。 - Lii
@Lii - 清空后,所有数组都是Object[]。这个技巧只是避免了强制转换。 - OldCurmudgeon
好的,看起来我误解了目的,抱歉。 "擦除后所有数组都是Object[]" 我不确定你在这里的意思。所有泛型类型的数组在运行时都将是Object[]。但其他类型,如Double[]double[]将具有这些运行时类型。擦除只涉及泛型类型。 - Lii

1
创建具有正确运行时类型的数组需要某种该类型的运行时表示。像 Foo<N> 这样的泛型类没有 N 的运行时表示。
有两个解决方案:
  1. 使用 List<N>。如果可能,这是最好的选择!
  2. 通过将 Class<N> 传递给 Foo,手动添加 N 的运行时表示,并使用 java.lang.reflect.Array.newInstance 创建数组。
第二种解决方案的代码:
public Foo(Class<N> newDataClass) {
    data = (N[]) Array.newInstance(newDataClass, 2);
}

Foo<Double> foo = new Foo<>(Double.class);

编辑:

如果你想要的是获取现有 Double 数组的副本,你可以使用 (N[]) data.clone()。设置它不会有问题。


1
一种方便但冗长的方法是将构造函数更改为使用数组类型的虚拟参数,因为你知道它在主方法中是double类型。
  public class Foo<N> {
         N[] data;

         public Foo(N inType) {
             data = (N[]) Array.newInstance(inType.getClass(), 2) ;
         }

         public N[] get() {
             return (N[]) data;
         }

         public void set(N[] data) {
             this.data = data;
         }

         public static void main(String[] args) {
             Foo<Double> foo = new Foo<Double>(new Double(0));
             Double[] d = foo.get();
             // do stuff to d ...
             foo.set(d);
         }

  }

0

泛型的问题在于,它在运行时没有任何特定类型。它只是类Object,这意味着创建这样的对象完全没有意义,因为实际上你只会创建一个Object类型的对象。

但是,您可以从类外部创建这样的对象,因为对象的真实类型在此处已知(Double)。因此,我建议使用某种动态的List来存储值。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接