Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/arrays/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
通过未经检查的类型转换在Java中创建泛型数组_Java_Arrays_Generics_Casting_Type Safety - Fatal编程技术网

通过未经检查的类型转换在Java中创建泛型数组

通过未经检查的类型转换在Java中创建泛型数组,java,arrays,generics,casting,type-safety,Java,Arrays,Generics,Casting,Type Safety,如果我有一个泛型类Foo,我不允许按如下方式创建数组: Bar[] bars = new Bar[]; (这将导致错误“无法创建Bar的通用数组”) 但是,正如dimo414在对的回答中所建议的,我可以做到以下几点: Bar[] bars = (Bar[]) new Object[]; (这将“仅”生成一条警告:“类型安全:未选中从对象[]强制转换到条[]”) 在回应dimo414答案的评论中,一些人声称在某些情况下使用此结构可能会导致问题,其他人则认为这很好,因为对数组的唯一引用是条,它已

如果我有一个泛型类
Foo
,我不允许按如下方式创建数组:

Bar[] bars = new Bar[];
(这将导致错误“无法创建Bar的通用数组”)

但是,正如dimo414在对的回答中所建议的,我可以做到以下几点:

Bar[] bars = (Bar[]) new Object[];
(这将“仅”生成一条警告:“类型安全:未选中从对象[]强制转换到条[]”)

在回应dimo414答案的评论中,一些人声称在某些情况下使用此结构可能会导致问题,其他人则认为这很好,因为对数组的唯一引用是
,它已经是所需的类型

我有点困惑,在哪种情况下这是可以的,在哪种情况下它会给我带来麻烦。例如,newacct和Aaron McDaid的评论似乎直接相互矛盾。不幸的是,原始问题中的评论流以未回答的“为什么这‘不再正确’?”结束,因此我决定为其提出一个新问题:

如果
条形图
-数组仅包含
条形图
类型的条目,那么在使用该数组或其条目时是否仍存在任何运行时问题?或者,唯一的危险是,在运行时,我可以从技术上将数组强制转换为其他类型(如
String[]
),这将允许我使用
Bar
以外的类型的值填充数组


我知道我可以使用
Array.newInstance(…)
,但是我对上面的类型转换构造特别感兴趣,因为,例如,在GWT中,
newInstance(…)
-选项不可用。

与列表相反,Java的数组类型是具体化的,这意味着
对象的运行时类型[]
不同于
字符串[]
。所以你写的时候,

Bar[] bars = (Bar[]) new Object[];

您已经创建了一个运行时类型为
Object[]
的数组,并将其“强制”到
Bar[]
。我在引号中说“cast”,因为这不是一个真正的checked cast操作:它只是一个编译时指令,允许您将
对象[]
分配到
Bar[]
类型的变量中。自然,这为各种运行时类型错误打开了大门。它是否真的会产生错误完全取决于你的编程能力和注意力。因此,如果你能胜任,那么就可以去做;如果您不这样做,或者此代码是许多开发人员的大型项目的一部分,那么这是一件危险的事情。

除非您希望在该数组中使用某种类型的
Bar
(或您初始化泛型类时使用的任何类型)而不是真正的
对象,否则一切正常。例如,具有以下方法:

<T> void init(T t) {
    T[] ts = (T[]) new Object[2];
    ts[0] = t;
    System.out.println(ts[0]);
}
它仍然运作良好;但是当您想要真正使用真正的T[]数组(在上面的示例中应该是String[]时):

然后您会遇到一个问题,因为
Object[]
String[]
是两个不同的类,您拥有的是
Object[]
,因此会抛出一个
ClassCastException

如果尝试有界泛型类型,问题会更快出现:

<T extends Runnable> void init(T t) {
    T[] ts = (T[]) new Object[2];
    ts[0] = t;
    System.out.println(ts[0]);
    ts[0].run();
} 
void init(T){
T[]ts=(T[])新对象[2];
ts[0]=t;
System.out.println(ts[0]);
ts[0]。运行();
} 

作为一个好的实践,尽量避免使用泛型和数组,因为它们不能很好地混合在一起。

好的,我已经使用了这个构造一段时间,它可能会非常混乱

我想我的问题的答案是:只要您始终将数组作为泛型处理,一切都可以正常工作。但一旦你尝试用非通用的方法来治疗它,就会有麻烦。让我举几个例子:

  • Foo
    中,我可以创建如图所示的数组,并且可以很好地使用它。这是因为(如果我理解正确的话)编译器“擦除”了
    -类型,并简单地将其转换为
    对象
    。因此本质上,在
    Foo
    中,您只是在处理一个
    对象[]
    ,这很好
  • 但是,如果在
    Foo
    中有这样一个函数,它提供了对阵列的访问:

    public Bar[]getbar(Bar){
    Bar[]结果=(Bar[])新对象[1];
    结果[0]=巴;
    返回结果;
    }
    
    如果你在其他地方使用它,你可能会遇到一些严重的问题。以下是一些疯狂的例子(大多数都是有道理的,但乍一看似乎很疯狂),你会发现:

    • String[]bar=new Foo().getbar(“Hello World”)

      将导致java.lang.ClassCastException:[Ljava.lang.Object;无法转换为[Ljava.lang.String

    • for(字符串栏:new Foo().getbar(“Hello World”)

      还会导致相同的java.lang.ClassCastException

    • 但是

      for(对象栏:new Foo().getbar(“Hello World”))
      System.out.println((字符串)条);
      
      工作

    • 有一个对我来说毫无意义:

      stringbar=newfoo().getbar(“Hello World”)[0];
      
      将导致java.lang.ClassCastException,即使我没有将其分配给任何地方的字符串[]

    • 甚至

      objectbar=newfoo().getbar(“Hello World”)[0];
      
      将导致相同的java.lang.ClassCastException

    • 只有

      Object[]temp=new Foo().getbar(“Hello World”);
      字符串条=(字符串)温度[0];
      
      工作

    顺便说一句,它们中没有一个会抛出编译时错误

  • 现在,如果您有另一个泛型类,那么:

    Baz类{
    Bar getFirstBar(Bar-Bar){
    Bar[]Bar=new Foo().getbar(Bar);
    返回条[0];
    }
    }
    
    以下几点效果不错:

    String bar=new Baz().getFirstBar(“Hello World”);
    
如果您意识到在类型擦除之后,
getbar(…)
-函数实际上返回了一个
Objec,那么这大部分都是有意义的
init("asdf");
String[] strings = init("asfd");
<T extends Runnable> void init(T t) {
    T[] ts = (T[]) new Object[2];
    ts[0] = t;
    System.out.println(ts[0]);
    ts[0].run();
} 
  Bar[] bars = (Bar[]) new Object[];
class Foo<Bar> {
    Bar[] get() {
       return (Bar[])new Object[1];
    }
}
void test() {
    Foo<String> foo = new Foo<>();
    String[] z = foo.get();
}
class Foo<Bar> {
    Bar[] bars = (Bar[])new Object[5];
    public Bar get(int i) {
        return bars[i];
    }
    public void set(int i, Bar x) {
        bars[i] = x;
    }
    public Bar[] getArray() {
        return bars;
    }
}

// in some method somewhere:
Foo<String> foo = new Foo<String>();
foo.set(2, "hello");
String other = foo.get(3);
String[] allStrings = foo.getArray();
class Foo {
    Object[] bars = new Object[5];
    public Object get(int i) {
        return bars[i];
    }
    public void set(int i, Object x) {
        bars[i] = x;
    }
    public Object[] getArray() {
        return bars;
    }
}

// in some method somewhere:
Foo foo = new Foo();
foo.set(2, "hello");
String other = (String)foo.get(3);
String[] allStrings = (String[])foo.getArray();