如果我有泛型类Foo<Bar>
,则不允许创建如下数组:
Bar[] bars = new Bar[];
(这将导致错误“无法创建Bar的通用数组”)。
但是,正如 dimo414
在回答该问题(Java如何:创建通用数组)中所建议的那样,我可以执行以下操作:
Bar[] bars = (Bar[]) new Object[];
(这将“仅”生成警告:“类型安全:未经检查从Object []到Bar []的转换”)。
在回应 dimo414
回答的评论中,有人声称使用此构造可能在某些情况下引起问题,而其他人则说这很好,因为对数组的唯一引用是bars
,它已经是所需类型了。
我有些困惑,在哪种情况下还可以,并且在什么情况下会给我带来麻烦。例如, newacct 和 Aaron McDaid
的评论似乎彼此矛盾。不幸的是,原始问题中的评论流仅以未回答的“为什么此’不再正确’?”结尾,所以我决定对此提出一个新问题:
如果bars
-array仅包含类型的条目Bar
,那么在使用数组或其条目时是否还会存在运行时问题?还是唯一的危险,那就是在运行时我可以将数组从技术上讲转换为其他内容(例如String[]
),然后允许我用非类型的值填充它Bar
?
我知道我可以使用它Array.newInstance(...)
,但是我对上面的类型转换构造特别感兴趣,因为,例如,在GWT中,newInstance(...)
-option不可用。
自从我在问题中被提及以来,我会插话。
基本上,如果不将此数组变量暴露给类的外部对象,则不会造成任何问题。(有点像,在拉斯维加斯发生的事情留在拉斯维加斯。)
数组的实际运行时类型为Object[]
。因此将其放入类型变量Bar[]
实际上是一个“谎言”,因为Object[]
它不是Bar[]
(除非Object
是Bar
)的子类型。但是,如果该谎言停留在班级内部,则可以,因为它Bar
已被删除到Object
班级内部。(下界的Bar
是Object
在这个问题上,在下界的情况Bar
是另一回事,更换所有出现Object
在这次讨论与任何该界是。)但是,如果这个谎言被莫名其妙地暴露于外(最简单的示例bars
直接将变量作为type
返回Bar[]
,则将导致问题。
要了解实际情况,有和没有泛型的代码都具有启发性。只需删除泛型并在正确的位置插入强制类型转换,即可将任何泛型程序重写为等效的非泛型程序。这种转换称为
类型擦除 。
我们考虑使用的简单实现Foo<Bar>
,其中包含用于获取和设置数组中特定元素的方法,以及用于获取整个数组的方法:
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();
因此,班级内不再有演员表。但是,在调用代码中有强制转换-
当获取一个元素并获取整个数组时。获得一个元素的强制转换应该不会失败,因为我们只能放入数组中Bar
,所以我们唯一也可以取出Bar
。但是,由于数组具有实际的运行时类型,因此在获取整个数组时进行强制转换将失败Object[]
。
非一般性地写,正在发生的事情和问题变得更加明显。尤其令人困扰的是,强制转换失败不会发生在我们使用泛型编写强制转换的类中,而是发生在使用我们类的其他人的代码中。该其他人的代码是完全安全无辜的。当我们在泛型代码中进行转换时,也不会发生这种情况,而是稍后有人在getArray()
没有警告的情况下调用它。
如果我们没有此getArray()
方法,则此类将是安全的。用这种方法,是不安全的。什么特征使其不安全?它bars
以type
返回Bar[]
,这取决于我们之前所做的“谎言”。由于谎言不是真的,因此会引起问题。如果该方法改为将数组返回为type
Object[]
,那么它将是安全的,因为它不依赖于“ lie”。
人们会告诉您不要像这样进行强制转换,因为它会导致意外异常(如上所示),而不是未经检查的强制转换的原始位置,导致强制转换异常。编译器不会警告您这getArray()
是不安全的(因为从它的角度来看,给定您所告诉的类型,它是安全的)。因此,这取决于程序员对这种陷阱的勤奋工作,而不是以不安全的方式使用它。
但是,我认为这在实践中并不是一个大问题。任何设计良好的API都不会将内部实例变量暴露给外部。(即使有一种方法将内容作为数组返回,它也不会直接返回内部变量;而是会复制它,以防止外部代码直接修改该数组。)因此,getArray()
无论如何都不会实现任何方法。
问题内容: 我已将Netbeans设置为在我的Java代码中显示未经检查的警告,但是我无法理解以下几行的错误: 给出: 方法来源: 到底出了什么问题,我想如何解决呢?因为我认为在代码中留下未经检查的警告不是一个好主意? 忘了提,但我使用的是Java 7。 编辑 :我现在也看到该方法具有以下内容: 问题答案: 如上面的janoh.janoh所述,Java中的varargs只是数组的语法糖,以及在调用
问题内容: 我有以下代码行 哪里 但我收到有关未经检查的转化的警告。如何停止此警告? 问题答案: 之所以会这样,是因为getSpecialCharMap()返回的对象的类型不能由编译器验证为HashMap 。继续并提供getSpecialCharMap的原型。
嗨,我在泛型类型和从IDE得到的警告方面有问题。我有一个保存泛型类型值的类: 我有一个抽象类: 以及扩展它的类: IDE警告我:未经检查的重写返回类型需要未经检查的转换。我错过了什么?
问题内容: 我想在Java中创建一个通用数组,以维护通常由Java提供的类型安全。 我正在使用此代码: 此代码类型安全吗?如果是这样,为什么?为什么它是类型安全的,我需要强制转换? 问题答案: 该方法的返回类型为。因此,您不能将其直接分配给以外的任何其他对象。因此,您需要演员表。 该方法委托给一个方法 创建具有指定组件类型和长度的新数组 因此,它正在创建一个type数组。 类型安全性,假设声明为
问题内容: 我正在尝试在java中创建一个通用数组-在其中我遇到了一些问题-我如何制作一个大小为6且里面有一个byte []和一个Integer的元组数组? 谢谢 问题答案: 好吧,您可以使用原始类型: 或者,您可以进行未经检查的转换: 或者,您也可以使用列表: 我建议改用列表。 在前两个选项之间进行选择,我建议您选择未经检查的转换,因为它将为您提供编译时检查。但是,如果将其他类型的元组放入其中,
问题内容: 在我的spring应用程序上下文文件中,我有类似以下内容: 在java类中,实现如下所示: 在Eclipse中,我看到一条警告: 类型安全性:未经检查的从Object到HashMap的转换 我做错了什么?我该如何解决该问题? 问题答案: 好吧,首先,你正在通过新的HashMap创建调用浪费内存。你的第二行完全忽略了对此创建的哈希图的引用,从而使该哈希图可用于垃圾收集器。因此,不要这样做