Creating generic arrays in Java through unchecked type conversion

If I have a general class foo < bar >, I do not allow the following to create an array:

Bar[] bars = new Bar[];

(this will result in the error "cannot create a generic bar array")

However, according to dimo414's suggestion in the answer to this question (Java how to: generic array creation), I can do the following:

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

(this will "only" generate a warning: "type security: unchecked conversion from object [] to bar []"

In the comments in response to dimo414, some people claimed that using this construction may lead to problems in some cases, while others said it was good because the only reference to the array was the bar of the required type

I'm a little confused. In this case, it's OK. Under what circumstances, it can get me into trouble For example, the comments of newacct and Aaron Mcdaid seem to contradict each other directly Unfortunately, the comment stream in the original question just ends with an unanswered "why is this no longer correct"? So I decided to ask a new question:

If bars array contains only the entry type bar, is there still a runtime problem when using the array or its entries? Or is it the only danger that at runtime, I can technically convert the array to something else (such as string []), which will allow me to fill in values of types other than bar?

I know I can use array Newinstance (...), but I am particularly interested in the above type conversion structure because, for example, in GWT, the newinstance (...) – option is not available

Solution

I'll come in after I mention it

Basically, if you don't expose this array variable outside the class, it won't cause any problems (a bit like what happened in Las Vegas)

The actual runtime type of the array is object [] Therefore, putting it in a bar [] variable is actually a "lie", because object [] is not a subtype of bar [] (unless object is bar) However, if it stays in class, the lie is OK, because bar is erased to object in class (in this problem, the lower limit of bar is object. When the lower limit of bar is other, replace all objects with all restrictions in this discussion.) However, if this lie is exposed to the outside in some way (the simplest example is to directly return the bar variable, such as the bar [] type), it will cause problems

To understand what's really happening, it's instructive to look at the code with and without generics Any imitation program can be rewritten into an equivalent non generic program by deleting the generic code and inserting the code into the correct location This conversion is called type erasure

We consider using the simple implementation of foo < bar >, as well as the method for obtaining and setting specific elements in the array and the method for obtaining 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();

When the type is erased, 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();

So there are no more actors in the class However, there are some variables in the calling code - get an element and get the entire array Actors who get an element should not fail, because the only thing we can put into the array is bar, so the only thing we can get is bar However, when getting the entire array, the conversion will fail because the array has the actual runtime type object []

Written in general, what happened and the problem became more obvious What is particularly worrying is that there is no actor failure in the actor's class we write with generics - it happens in the code of someone else who uses our class And the person's code is completely safe and innocent Nor will it happen when we convert in generic code - it will happen later, without warning when someone calls getarray ()

If we don't have this getarray () method, this class will be safe It is not safe to use this method What makes it unsafe? It returns a bar of type bar [], depending on what we've done before Because the lie is incorrect, it causes problems If the method has returned an array of type object [], it will be safe because it does not depend on "lie"

People will tell you not to do this because it will cause exceptions in the unexpected places above, not in the original places of the unselected actors The compiler will not warn you that getarray () is unsafe (because from its point of view, given the type you tell it, it is safe) Therefore, it depends on the programmer's efforts to this trap, rather than using it in an unsafe way

But I don't think this is a big problem Any well - designed API does not expose internal instance variables to the outside world (even if there is a method to return the contents as an array, it will not directly return internal variables; it will copy it to prevent external code from directly modifying the array) so it is not like getarray()

The content of this article comes from the network collection of netizens. It is used as a learning reference. The copyright belongs to the original author.
THE END
分享
二维码
< <上一篇
下一篇>>