Domanda

I've heard here and there that arrays contain runtime data about their type, making you unable to instantiate an E[] (E being a generic type parameter, for example in a class Foo<E>), and that while you can achieve the same effect by doing (E[]) new Object[n], it is bad, which is why the compiler raises a warning. I'm having trouble thinking of what exactly could go wrong (famous last words), so could someone give an example of how a program could become defective because of instantiating Object[]s and casting them to E[]?

È stato utile?

Soluzione

If the array is only used within the inside of the class, and the fact of the variable's type as E[] is never exposed outside the class (e.g. returned in a method, or it is a public or protected field, etc.), then there is no problem as inside the class E is erased.

However, if you expose the fact of the array variable's type as E[] to the outside of the class, then it can go into a context where they have a concrete type for your E, and rightly believe that what they are getting is that type of array, and it will throw a ClassCastException without any warning in that outside code. The simplest example is a method that simply returns the array as E[], and it is called from outside code that has a concrete type as the type parameter; a ClassCastException is thrown from the outside code without any warning in that outside code or in the method that returns the array:

public class Foo<E> {

    private E[] myArray = (E[])new Object[42];

    public E[] getArray() {
        return myArray;
    }

}

// some outside code:
Foo<String> foo = new Foo<String>();
String[] stringArray = foo.getArray(); // ClassCastException

Altri suggerimenti

You could, of course, declare the array as Object[], and write a private accessor like

Object[] elements = ...;

@SuppressWarnings("unchecked")
private E getElement(int index)
{
    return (E)elements[index];
}

This way, you don't have a field with declaration that lies to you and every other reader of your code, and confine the cast to a single place. The cast is a no-op, btw., because there's no way for the compiler to do a real actual cast to a non-reified type.

This is in fact exactly what goes on inside many well-written collection implementations.

The cast to E[] can have performance benefits for a real actual collection, so it is the way to go in those few places where you write code that influences lots of other code, performance-wise.

Use comments, because exceptional things are the one area where they can be valuable. Restrain the field's scope. Think thrice about what you're doing in any step, and you should be fine :)

In case performance is NOT paramount, though, just use the accessor 😬

Autorizzato sotto: CC-BY-SA insieme a attribuzione
scroll top