如何创建通用数组? [复制]

Posted

技术标签:

【中文标题】如何创建通用数组? [复制]【英文标题】:How to create generic array? [duplicate] 【发布时间】:2012-08-14 18:31:36 【问题描述】:

可能重复:Java how to: Generic Array creation

如何在Java中创建T[]类型的数组?我不能使用Arrays.newInstance(),因为我没有Class<T> 的对象。在某处是否有newInstance 的通用版本?

我的方法原型如下:

public <T> T[][] distribute(T ... balls) 
   T[][] answer = ????

   // filling answer with data

   return answer;


更新

对不起,在上面的例子中,我可以从balls 上课。但是假设我没有这样的变量。

public <T> T[][] distribute() 
   T[][] answer = ????

   // filling answer with data

   return answer;


class<T> 
   public T[][] distribute() 

      T[][] answer = ????

      // filling answer with data

      return answer;

   

更新2

这个例子也不行:

public abstract class GenericArray<T> 

abstract public T create();

public T[] gen1() 
    T[] ans = (T[]) new Object[3];
    ans[0] = create();
    ans[1] = create();
    ans[2] = create();
    return ans;


public Integer[] gen2() 
    Integer[] ans = new Integer[3];
    ans[0] = new Integer(0);
    ans[1] = new Integer(0);
    ans[2] = new Integer(0);
    return ans;


public static void main(String[] args) 

    GenericArray<Integer> a = new GenericArray<Integer>() 

        @Override
        public Integer create() 
            return new Integer(0);
        
    ;

    Integer[] b = a.gen2();
    Integer[] c = a.gen1(); // this causes ClassCastException

    System.out.println("done");




【问题讨论】:

为什么你不能从balls 可变参数之一获得Class&lt;T&gt;,假设有一个? if(balls.length &gt; 0) Class&lt;T&gt; clazz = balls[0].getClass(); 无论如何,你不可避免地会听到“数组和泛型不能很好地结合在一起”。 最简单的方法是不使用数组,使用某种Collection 【参考方案1】:

1. Arrays不是 Generic

2.这就是Arrays在编译和运行时被检查的原因,其中Collections可以是通用仅在编译期间检查....

【讨论】:

那么在只有generoc信息的情况下不可能创建一个类型的数组? 你可以使用类似@SuppressWarnings("unchecked") B&lt;Integer&gt;[] arr = new B[3];的东西,但你需要禁止编译器警告....但是为什么在运行时不存在通用信息时这样做,而且我不喜欢使用我在java中工作时的数组。集合提供了更大的灵活性 是的。或者,更准确地说:您没有泛型信息开始,因为它在运行时被删除(至少在纯 java 中)。这是一个编译时特性,一旦你的应用程序运行就完全失去了。 @sarcan ya...该过程称为Erasure,其中compiler removes the Type Parameter and Argument Parameters from the class , method, etc..。使其成为原始类型(原始类型是没有类型参数的泛型类或接口名称【参考方案2】:

(T[][]) new Object[size][size]

【讨论】:

【参考方案3】:

你问的是不可能的。数组在运行时知道它的组件类型,不同组件类型的数组是不同的运行时类型。这就是为什么在创建数组时,需要在运行时知道组件类型。

由于您的方法对T 是通用的,因此调用者可以在每次调用此方法时向编译器指示它想要使用的T。所以想想这是多么荒谬:

String[][] foo = this.<String>distribute();
Integer[][] bar = this.<Integer>distribute();

右侧的编译代码对于这两行是相同的。 .&lt;String&gt; 只是对编译器的提示,不会影响编译后的代码。所以这意味着distribute() 必须返回String[][]Integer[][] 的东西(然后在运行时检查,因为String[][]Integer[][] 是具体化的运行时类型)。唯一可以满足这一点的值是null

(你可能会问,为什么返回List&lt;T&gt;的方法不会出现这个问题?答案是,与数组不同,在运行时只有一个类List。并且列表不知道它们的组件类型在运行时。所以 new ArrayList&lt;Foo&gt;()new ArrayList&lt;Bar&gt;() 在运行时完全相同。所以它们没有这个问题。)

这里发生的另一个类比:因此数组类型具有遵循其组件类型继承的继承模式。所以Integer[][]Object[][] 的子类。事实上,所有T[][] 都是Object[][] 的子类。因此,让我们考虑一个非数组类MyBaseClass,而不是Object[][] 及其子类,它有一堆子类。然后,您基本上要问的是能够一般地创建MyBaseClass 的未知子类的实例(由类型参数确定)。

<T extends MyBaseClass> T distribute() 
    T answer = //...?
    return answer;

我希望你能明白为什么这是不可能的。

【讨论】:

【参考方案4】:

执行:T[][] answer = (T[][]) new Object[][];T 无论如何都会被编译器擦除为Object。当然你需要知道数组的大小。

更新: 在您的新示例中,您会在此处遇到异常:Integer[] c = a.gen1(); // this causes ClassCastException 因为您试图将Object[] 转换为Integer[]。不可能。 你得到的是一个Object[],但包含Integer 引用。所以你需要这样做:

Object[] c = a.gen1();
for(Object n:c)  
    Integer nn = (Integer) n;  
  

这没关系,因为nInteger。 但作为一般规则:如果您需要收集参数化类型对象,只需使用ArrayList。在您的示例中,您甚至没有实际的 class 来通过反射实例化数组,这是唯一明智的选择

【讨论】:

这不会在运行时导致ClassCastException 吗? 否,因为类型参数T 将被编译器删除,并且无论如何都会被Object 替换。这称为type-erasure。您正在将特定对象添加到@ 987654338@数组是合法的 @Dims 仅当您尝试将其分配给T的具体类型时才会导致ClassCastExceptionString[] foo = foo(); public static &lt;T&gt; T[] foo() return (T[]) new Object[5]; @Jeffrey @user384796 我试过了,它导致了ClassCastException。我需要创建普通类型的普通数组。

以上是关于如何创建通用数组? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

如何创建通用数组以添加任何视图

如何创建这样的矩阵? [复制]

如何创建数组的副本? [复制]

如何在 C# 中删除(或取消)泛型数组列表中的对象? [复制]

python - 重复numpy数组而不复制数据

如何创建一个与 numpy 数组重叠 50% 的滑动窗口? [复制]