Java 通用数组创建

Java 通用数组创建,java,arrays,generics,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]; ... } } 公共类aCla

这是我正在使用的代码

public class aClass<T> {

    private T[] elements;

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

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

}
公共类aClass{
私有T[]元素;
公共aClass(T[]个元素){
这个元素=元素;
}
公共无效剂量测定法(){
T[]newArray=(T[])新对象[5];
...
}
}
我看到有人说创建这样的数组是个坏主意,因为它不是类型安全的。然而,每次我使用它,我都没有问题。什么时候创建这样的数组会导致问题


谢谢

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

一些不安全的类型本身不会产生问题。但它可以在编译时隐藏问题,直到合适的时候才会弹出


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

其他人是错的。除非在创建时有该类型的实例,否则没有其他方法来创建数组。另见

如果您有类型实例(=具有类型
Class
),您可以调用
java.lang.reflect.Array.newInstance(Class,int)
,但即使这样,您也需要强制转换,为什么还要麻烦呢

如果
元素
的类型是
对象
而不是
T
,我会说情况就不同了,但既然不是这样,代码就完全可以了

如果要进一步隐藏此内容,可以编写帮助器方法:

  @SuppressWarnings( "unchecked" )
  public static <T> T[] createArray( int size ) {
      return (T[]) new Object[size];
  }
@SuppressWarnings(“未选中”)
公共静态T[]createArray(整数大小){
返回(T[])新对象[大小];
}

在调用数组时不需要强制转换就可以创建数组。

在这种情况下,使用
集合
更安全。做点像

...
Collection<T> newElements = new ArrayList<T>(5);
...
。。。
集合新元素=新数组列表(5);
...

无论如何,据我所知,创建这样的泛型数组不会给您带来真正的问题,但“味道很糟糕”,因为它需要显式类型转换。在这种情况下,您真的需要一个数组吗?

您不能创建一个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);
    }
}

下面是一个导致问题的示例:

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);
    }
}
公共类主{
公共静态类列表{
私人E[]myE;
公共空间(E){
E[]新数组=(E[])新对象[5];
for(int i=0;i
代码之所以有效,是因为当您声明泛型参数
时,它是未绑定的,这意味着它扩展了
对象
。当您将数组强制转换为
(T[])
时,实际上是在将数组强制转换为
(Object[])
,因为这是编译器所能做的最好的操作。现在,如果将数组保存在代码中,就不会有太多问题。但是,如果代码外部的某个人可以检索该数组,并使用object以外的类型实例化了您的类,那么他将拥有ClassCastException

我见过有人说,创建这样的数组是一个坏主意 想法,因为它不是类型安全的。然而,每次我使用它,我 没有问题。什么时候创建这样的数组会导致 有问题吗

人们说这是个坏主意,因为从逻辑上讲,如果
T
不是
object
,那么将运行时类型为
object[]
的对象强制转换为
T[]
类型是不正确的

但是,您没有看到任何直接的问题,因为在类内部(在
T
的范围内,
T
被擦除。因此,不会检查从
Object[]
T[]
的强制转换

如果您所做的只是在类内使用这个变量(在类型变量
T
的范围内),并且您从不将它返回给类外的人,并且类外的人无法访问它,那么它将不会导致任何问题

事实上,这样做有很多好处——在获取和设置数组元素时,您可以获得泛型类型检查的所有好处,如果您只是简单地遵循使用类型为
Object[]
的变量的完全“类型安全”解决方案,您将无法获得这些好处,在这种情况下,您必须手动转换从中获得的内容

如果您以type
T[]
的形式将此数组变量返回外部(或允许外部访问它),您将遇到问题,因为调用代码需要某种类型的数组,泛型将在收到此数组时在调用代码中插入强制转换,而强制转换将在运行时失败(例如,
对象[]
不是
字符串[]
;它们在运行时是不同的类型)。下面是一个简单的示例:

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
公共a类
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