通用阵列创建

时间:2012-04-05 15:45:45

标签: java arrays generics

这是我正在使用的代码

public class aClass<T> {

    private T[] elements;

    public aClass(T[] elements) {
        this.elements = elements;
    }

    public void doSomething() {
        T[] newArray = (T[]) new Object[5];
        ...
    }

}

我见过有人说创建像这样的数组是一个坏主意,因为它不是类型安全的。但是,每次我使用它,我都没有问题。何时创建这样的数组会导致问题?

由于

7 个答案:

答案 0 :(得分:4)

你不能创建一个T数组,因为Java在运行时不知道什么是T的类型。这是因为Java泛型是用类型擦除实现的。这意味着在确保一切正常后,编译器会丢弃大多数泛型类型信息。

对于数组,故事是不同的,因为Java需要知道T的确切类型才能创建给定的数组,并且由于无法确定这样的事情,所以无法创建泛型类型的数组。

您可以做的是提供要使用的实际数组的实例,Java编译器可以确保它具有适当的类型:

public static <T> void fillWith(T[] destiny, List<? extends T> source){
    for(int i=0; i<= destiny.length; i++){
        destiny[i] = source.get(i);
    }
}

java.utils.Arrays.copy方法提供了一种使用泛型和反射的替代方法,您可以将其用作您想要做的参考。

public static <T> T[] copyOf(T[] original, int newLength) {
   return (T[]) copyOf(original, newLength, original.getClass());
}


public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {
        T[] copy = ((Object)newType == (Object)Object[].class)
            ? (T[]) new Object[newLength]
            : (T[]) Array.newInstance(newType.getComponentType(), newLength);
        System.arraycopy(original, 0, copy, 0,
                         Math.min(original.length, newLength));
        return copy;
}

答案 1 :(得分:4)

以下是导致问题的示例:

public class Main {

    public static class List<E extends Number> {

        private E[] myE;

        public void hello(E e) {
            E[] newArray = (E[]) new Object[5];
            for (int i = 0; i < newArray.length; i++) {
                newArray[i] = e;
            }
            myE = newArray;
        }

    }

    public static <T> T[] createArray(int size) {
        return (T[]) new Object[size];
    }

    public static void main(String[] args) throws IOException {
        List<Integer> integers = new List<Integer>();
        integers.hello(5);
    }
}

您的代码有效,因为当您声明通用参数<T>时,它是未绑定的,这意味着它扩展了Object。当您将数组转换为(T[])时,实际上是在转换为(Object[]),因为这是编译器可以做的最好的。现在,如果将数组保留在代码中,则不应该有太多问题。但是,如果代码外部的某个人可以检索该数组并使用除object之外的类型实例化您的类,则他将具有ClassCastException。

答案 2 :(得分:2)

不安全的东西本身并不会产生问题。但它可以在编译时隐藏问题,直到合适的时刻才能弹出。

您可以在没有问题的情况下在非安全的环境中完全工作,但这只是一个坏习惯,因为类型安全的环境确保您不会拥有一组公共运行时错误,你现在没有,但你没有任何保证,这些非常重要,任何你可以信赖的安全意味着更少的努力。

答案 3 :(得分:1)

其他人错了。除非在创建时有类型的实例,否则没有其他方法可以创建数组。另请参阅How to create a generic array in Java?

如果您有类型实例(=具有类型Class<T>的东西),您可以调用java.lang.reflect.Array.newInstance(Class<?>, int),但即便如此,您还需要演员,所以为什么要这么麻烦?

如果elements的类型是Object而不是T,我会说情况有所不同,但事实并非如此,代码完全没问题。

如果你想进一步隐藏它,你可以写一个辅助方法:

  @SuppressWarnings( "unchecked" )
  public static <T> T[] createArray( int size ) {
      return (T[]) new Object[size];
  }

当你调用它时,它会创建一个不需要强制转换的数组。

答案 4 :(得分:1)

在这种情况下使用Collection会更安全。只需制作类似

的内容
...
Collection<T> newElements = new ArrayList<T>(5);
...

无论如何,从我所知道的创建像这样的通用数组不会给你带来真正的问题,但是“闻起来很糟糕”,因为它需要显式的类型转换。在这种情况下你真的需要一个阵列吗?

答案 5 :(得分:1)

  

我见过有人说创建这样的数组是件坏事   这个想法,因为它不是类型安全的。但是,每次我使用它,我   没问题。何时会像这样创建一个数组   一个问题?

人们说这是一个坏主意,因为从逻辑上讲,如果Object[]不是T[],则将运行时类型为T的对象转换为Object类型是不正确的}。

但是,您没有看到任何直接问题,因为在课堂内(T范围内),T被删除。因此,不会检查从Object[]T[]的演员表。

如果您所做的只是在您的类中使用此变量(在类型变量T的范围内),并且您永远不会将它返回给类外的人,并且除了class可以访问它,然后它不会导致任何问题。

事实上,你正在做的方式有好处 - 在获取和设置数组的元素时,你可以获得泛型类型检查的所有好处,如果你只是按照完全“类型”就不会得到-safe“使用类型为Object[]的变量的解决方案,在这种情况下,您必须手动转换从中获取的内容。

如果您将此数组变量返回到外部(或以其他方式允许外部访问它)作为类型T[],您将遇到问题,因为调用代码将期望某种类型的数组,并且泛型将在接收到此数组时在调用代码中插入强制转换,并且强制转换将在运行时失败(因为例如Object[]不是String[];它们在运行时是不同的类型。这是一个简单的例子:

public class aClass<T> {

    private T[] elements;

    public aClass(T[] elements) {
        this.elements = elements;
    }

    public void doSomething() {
        elements = (T[]) new Object[5];
        ...
    }

    public T[] getArray() {
        return elements;
    }

}

// some other code...
aClass<String> foo = new aClass<String>(new String[2]);
foo.doSomething();
String[] bar = foo.getArray(); // ClassCastException here

答案 6 :(得分:0)

您可能在比较和打印时遇到问题..基本上任何知道类型对格式化很重要的时候。你有它的方式系统不知道数组中的数据

相关问题