通过创建选中类型转换使用Java泛型数组 [英] Creating generic array in Java via unchecked type-cast

查看:170
本文介绍了通过创建选中类型转换使用Java泛型数组的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

如果我有一个泛型类美孚<酒吧GT; ,我不能创建一个数组如下:

If I have a generic class Foo<Bar>, I am not allowed to create an array as follows:

Bar[] bars = new Bar[];

(这将导致错误无法创建酒吧的通用阵列)。

(This will cause the error "Cannot create a generic array of Bar").

但是,正如 dimo414 的在回答建议这个问题(Java的如何:通用阵列创建),我可以做到以下几点:

But, as suggested by dimo414 in an answer to this question (Java how to: Generic Array creation), I can do the following:

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

(这将只有生成一个警告:类型安全:未选中从Object施放[]吧[])。

(This will "only" generate a warning: "Type safety: Unchecked cast from Object[] to Bar[]").

在评论回应的 dimo414 的的回答,一些人声称,使用这种结构可能会导致在某些情况下的问题,有人说这很好,因为到阵列的唯一参考酒吧,这已经是所需类型的。

In the comments responding to dimo414's answer, some people claim that using this construct can cause problems in certain situations and others say it's fine, as the only reference to the array is bars, which is of the desired type already.

我有点糊涂了在哪些情况下,这是确定并在哪些情况下可以运行我陷入麻烦。通过这些评论的 newacct 的和的亚伦McDaid 的,例如,似乎直接相互矛盾。不幸的是在原来的问题注释流简单地结束悬而未决这是为什么不再是正确的?,所以我决定做一个新的问题吧:

I'm a little confused in which cases this is OK and in which cases it can run me into trouble. The comments by newacct and Aaron McDaid, for example, seem to directly contradict each other. Unfortunately the comment stream in the original question simply ends with the unanswered "Why is this 'no longer correct'?", so I decided to make a new question for it:

如果在酒吧 -array永远只能包含酒吧类型的项目,可能还有任何运行时使用数组或它的条目时的问题?或者是唯一的危险,即在运行时,我可以在技术上投下的阵列到别的东西(如的String [] ),那么这将让我用值填充比酒吧

If the bars-array only ever contains entries of type Bar, could there still be any run-time issues when using the array or its entries? Or is the only danger, that at run-time I could technically cast the array to something else (like String[]), which would then allow me to fill it with values of a type other than Bar?

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

I know I can use Array.newInstance(...) instead, but I am specifically interested in the type-casting construct above, since, for example, in GWT the newInstance(...)-option isn't available.

推荐答案

,我会附和

基本上,它不会引起任何问题,如果你没有这个数组变量暴露在类的外部。 (有点像,会发生什么事在拉斯维加斯停留在拉斯维加斯。)

Basically, it will not cause any problems if you don't expose this array variable to the outside of the class. (kinda like, What happens in Vegas stays in Vegas.)

数组的实际运行时类型为对象[] 。所以,把它变成键入酒吧[] 的变量实际上是一个谎言,因为对象[] 不是的一个亚型酒吧[] (除非对象酒吧 )。然而,这种谎言是好的,如果它停留在类中,因为酒吧擦除为对象里面的类。 (下界酒吧对象在这个问题上,在达到了下界的情况下酒吧是另一回事,替换对象中出现的所有的讨论与任何的约束是。)但是,如果这个谎言被莫名其妙地暴露到外面(最简单的例子是返回酒吧变量直接作为类型酒吧[] ,那么就会造成问题

The actual runtime type of the array is Object[]. So putting it into a variable of type Bar[] is effectively a "lie", since Object[] is not a subtype of Bar[] (unless Object is Bar). However, this lie is okay if it stays inside the class, since Bar is erased to Object inside the class. (The lower bound of Bar is Object in this question. In a case where the lower bound of Bar is something else, replace all occurrences of Object in this discussion with whatever that bound is.) However, if this lie gets somehow exposed to the outside (the simplest example is returning the bars variable directly as type Bar[], then it will cause problems.

要了解什么是怎么回事,它是有启发看code使用和不使用泛型。任何泛型程序可以改写成等价的非泛型程序,只需通过删除泛型和在正确的位置插入转换。这种转变就是所谓的类型擦除

To understand what is really going on, it is instructive to look at the code with and without generics. Any generics program can be re-written into an equivalent non-generics program, simply by removing generics and inserting casts in the right place. This transformation is called type erasure.

我们考虑一个简单的执行美孚&LT的;酒吧GT; ,以获取和设置数组中的特殊元素,以及用于获取整个阵列的方法方法:

We consider a simple implementation of Foo<Bar>, with methods for getting and setting particular elements in the array, as well as a method for getting the whole array:

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();

类型擦除后,这将成为:

After type erasure, this becomes:

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();

因此​​,有阶级内部没有蒙上了。不过,也有在调用code的演员 - 让一个元素时,并获得整个数组。演员获得一个元素不应该失败,因为我们可以把入阵的唯一的东西是酒吧,所以唯一的事情,我们可以走出也在酒吧。不过,中投获取整个阵列时,这将失败,因为阵中拥有实际运行时类型对象[]

So there are no casts inside the class anymore. However, there are casts in the calling code -- when getting one element, and getting the entire array. The cast to get one element should not fail, because the only things we can put into the array are Bar, so the only things we can get out are also Bar. However, the cast when getting the entire array, that will fail, since the array has actual runtime type Object[].

写非一般,发生什么事,这个问题变得更加明显。什么是特别令人不安的是,中投故障不会在课堂上发生的,我们写了仿制药的演员 - 它发生在别人使用我们的类code。而其他人的code是完全安全的,无辜的。 ,它也不会在那里我们做了我们在仿制药code投时有发生 - 它后来发生了,当有人呼叫的getArray(),没有警告

Written non-generically, what is happening and the problem become much more apparent. What is especially troubling is that the cast failure does not happen in the class where we wrote the cast in generics -- it happens in someone else's code that uses our class. And that other person's code is completely safe and innocent. It also does not happen at the time where we did our cast in the generics code -- it happens later, when someone calls getArray(), without warning.

如果我们没有这个的getArray()方法,那么这个类将是安全的。用这种方法,这是不安全的。什么特性使得它不安全?它返回酒吧类型酒吧[] ,这取决于谎言,我们提前进行。因为谎言是不正确的,它会导致问题。如果该方法有,而不是返回的数组类型对象[] ,那么这将是安全的,因为它不依赖于谎言。

If we didn't have this getArray() method, then this class would be safe. With this method, it is unsafe. What characteristic makes it unsafe? It returns bars as type Bar[], which depends on the "lie" we made earlier. Since the lie is not true, it causes problems. If the method had instead returned the array as type Object[], then it would be safe, since it does not depend on the "lie".

人会告诉你不要做这​​样的投这样的,因为它会导致在意想不到的地方投例外上面所看到的,而不是在原来的地方,选中演员阵容。编译器不会警告你,的getArray()是不安全的(因为从它的角度来看,因为你告诉它的类型,它是安全的)。因此,它取决于程序员勤于这个陷阱,而不是在不安全的方式来使用它。

People will tell you to not do such a cast like this, because it causes cast exceptions in unexpected places as seen above, not in the original place where the unchecked cast was. The compiler will not warn you that getArray() is unsafe (because from its point of view, given the types you told it, it is safe). Thus it depends on the programmer to be diligent about this pitfall and not to use it in an unsafe way.

不过,我认为这是在实践中没有一个大问题。任何精心设计的API将永远不会暴露内部实例变量到外部。因此,没有方法将(从直接修改数组,将它复制到prevent之外code即使有返回的内容作为一个数组的方法,它不会直接返回内部变量)。像的getArray()实施反正。

However, I would argue that this is not a big concern in practice. Any well-designed API will never expose internal instance variables to the outside. (Even if there is a method to return the contents as an array, it would not return the internal variable directly; it would copy it, to prevent outside code from modifying the array directly.) So no method will be implemented like getArray() is anyway.

这篇关于通过创建选中类型转换使用Java泛型数组的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆