1

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[]?

8
  • You might want to edit to indicate that E is a generic type parameter.
    – Erik Eidt
    Sep 15, 2016 at 1:49
  • 2
    What is the X Y Problem? Sep 15, 2016 at 2:43
  • @RobertHarvey My problem is my computer science professor telling his class to create E[] by casting Object[]
    – Phoenix
    Sep 15, 2016 at 2:47
  • 1
    Do what your teacher says to pass the class. Do it the right way later. See also stackoverflow.com/a/30096771 Sep 15, 2016 at 2:53
  • He's not requiring us to do that, he's just suggesting it as a good practice.
    – Phoenix
    Sep 15, 2016 at 2:57

2 Answers 2

3

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
0

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 😬

3
  • I just looked inside a collection I've recently written, and I also used a cast to E[] 😂
    – yeoman
    Sep 15, 2016 at 6:07
  • Will change that immediately...
    – yeoman
    Sep 15, 2016 at 6:07
  • Nope, i take that back. There's been performance reasons for casting to E[]. So just be careful about it :)
    – yeoman
    Sep 15, 2016 at 6:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.