Question

Generally, Java can be considered as a type-safe language. I know that there are some flaws with generics, but I recently came across a Problem I never had before. To break it down:

Object[] objects = new Integer[10];
objects[0] = "Hello World";

will NOT result in a compile-time error as expected. I would assume that the declaration of an Array of Object will disallow to point to to an array of something else. In Generics I'm not allowed to make such weird things like:

ArrayList<Object> objs = new ArrayList<Integer>

and if I try to kind of trick Java into doing something with

ArrayList<? extends Object> objects = new ArrayList<Integer>

I'm allowed to declare it, but I can only add Objects of type null.

Why doesn't Java prevent the declaration of such weired arrays?

Was it helpful?

Solution 2

I don't think there's an answer to this besides "legacy design". (Which I admit is a fancy way of saying "because".) You pretty much need to be able to do an equivalent of the last assignment you show somehow. (Otherwise you're stuck to making lots and lots of copies with manual up/down casts, assuming language features of Java pre 1.4)

In Java 1 when type semantics for arrays were basically set in stone, generics weren't available, or even up for consideration for a long while yet. So there was no mechanism available to express the higher-order type constraints needed to make this construct type-safe – and Gosling (IIRC a fan of simplicity) felt resolving this edge case of compile-time type safety wasn't worth complicated the language with whichever solutions were available. Or wasn't bothered by doing the check at runtime enough to even look for a solution. (At the end of the day language design decisions are arbitrary to at least some degree, and there's only one person that could answer this with any certainty.)

OTHER TIPS

Firstly, I should point out that this is type-safe.

Object[] objects = new Integer[10];
objects[0] = "Hello World";

because an exception will be thrown. (It is not statically type-safe ... but that is a different statement entirely.)

The reason that Java allows this is historical. Until Java 5, Java did not support any form of generics. Gosling has said that if they had had the time to figure out and incorporate generics into Java 1.0, they would have done so.

Unfortunately, they didn't. But they still wanted to be able write things like a general purpose sort method with the following signature:

    void sort(Object[] array, Comparator comp) ...

To make this method work for any kind of object array (without generics), it was necessary to make arrays covariant; i.e. to make it legal to pass a String[] or Integer[] as an argument where the formal type is Object[]. If they hadn't done that you would have had to copy the String[] to an Object[], sort it, and then copy it back.

"Because it has to".

To elaborate a bit, consider the following example:

Object[] objects = null;
if (something) {
    objects = new Integer[10];
} else {
    objects = new String[10];
}

Now, how would the Java compiler know which assignments to allow and which to refuse? It can't. The compile-time type is Object so the compiler will let you put any Object in your array, simply because it doesn't have any knowledge of the runtime type of your array.

actually in case of arrays you get a exception at run time called ArrayStoreException when you add wrong type of element In this case a String. In case of generics there is no such exception. its for the very same reason you are not allowed to add anything but object, as you might just add a wrong type into the list.

There's Discussion that I found while I google it

I Found:

Firstly, arrays do not break type safety. If they did, then upcasting an array wouldn't fail at runtime. They make it impossible for the compiler to prove the program type-safe, so the checking is deferred until runtime.

I think confusion occurs here because one the one hand, since a String is-a Object an array of Strings is-obviously-an array of Objects, and on the other it clearly isn't. The answer is in the mutability of an array.

If the array is immutable, then it safe to treat a String[] as an Object[], because an immutable String[] is always exactly like an immutable Object[].

On the other hand, if the array is mutable, then it is not usually safe to treat a String[] as an Object[].

The "wildcards" technique described in the above link is exactly what CommonLisp has been doing for years.

(deftype StringArray? () (array String)) ; This is the type of arrays of String 
(deftype ObjectArray? () (array Object)) ; This is the type of arrays of Object 
(subtypep StringArray? ObjectArray?)      ; Is StringArray? a subtype of ObjectArray?? false, true                               ; No, it isn't. (false: it isn't, true: I'm ure) 
(deftype AnyArray? () (array *))         ; This is the type of arrays of anything (subtypep StringArray? AnyArray?)         ; Is StringArray? a subtype of AnyArray??   true, true                                ; Yes, it is. (true: it is, true: I'm sure)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top