1

Why does my attempt to add an Integer to a Java array, declared as an Object[] but instantiated as a String[], not generate a compilation error?

Object[] ob = new String[1];
ob[0] = new Integer(1); // this shouldn’t compile but it does!

When I run this, I get a runtime exception instead of a (much preferred) compile-time error! Is this correct behavior? Shouldn't I get a compile-time error?

5
  • 6
    ob is an Object[]. Integer is a subclass of Object. So that should compile perfectly fine. Perhaps you want to declare ob as String[] instead? Commented Jul 1, 2012 at 17:39
  • #HovercraftFullOfEels it is true what you say about poorly written code, but in other languages, C++ comes to mind you are protected by compiler from writing such a nonsense. And just to mention, this is simple example. In real world programs you couldn't possibly see all code at the same time. How could you know if you assinging right types to right containers? Commented Jul 1, 2012 at 17:46
  • @smallB: I don't know the answer to that, other than to declare the variable to the most general type possible, but no further. Commented Jul 1, 2012 at 17:48
  • 4
    I don't understand why this question was closed. It's a fully legitimate question about a pitfall of Java semantics. The main point that may be confusing you is the runtime type of the referenced array (String[]) vs. the compile-time type of the array variable (Object[]). The compiler only enforces that what you put into the array is compatible with the static type of the array variable refering to it. Commented Jul 1, 2012 at 17:51
  • I agree with @Marko, this is a valid question re Java, and that clarification of these principles can only help us all, and I have voted to re-open and have up-vote the question. The only reason I see to close this is if there is an exact duplicate somewhere. Commented Jul 1, 2012 at 17:55

2 Answers 2

3

It's a choice that Java designers have made: String[] extends Object[], but you can't add anything other than a String to an array whose concrete type is String[] without getting a runtime exception.

What they could have made invalid is the following:

Object[] ob = new String[1];

because it effectively allows any kind of object to be added to the array without getting any compiler error (as you noticed), which is perfectly normal since an Integer is an Object, and the compile-time type of the array is Object[].

They didn't make this choice for arrays, but they did it for generic collections:

List<Object> ob = new ArrayList<String>();

generates a compiler error, because List<String> doesn't extend List<Object>. Collections should generally be preferred over arrays, as they're safer, and provide a lot more functionality.

Sign up to request clarification or add additional context in comments.

2 Comments

The way I see it, OP's actual confusion lies with the compile-time vs. runtime type of the array. He thinks the compiler should prevent putting an Integer into a String array (doesn't have to do with array type covariance).
Yes. I've edited my answer to make that clearer. Thank you for the suggestion.
2

The main point that you may want to take into account is the runtime type of the referenced array (String[]) vs. the compile-time type of the array variable (Object[]). The compiler only enforces that what you put into the array is compatible with the static type of the array variable refering to it. This example makes that stand out:

String[] strs = new String[1]; 
Object[] objs = strs; 
strs[0] = new Integer(1); /* error, says the compiler! */ 
objs[0] = new Integer(1); /* fine by me, says the compiler! */

Now, what you should legitimately be upset about is actually your first line: Object[] ob = new String[1]; which implies that String[] is assignment-compatible with Object[]—in other words, its subtype. This is in opposition with the well-known fact of CS that container types are contravariant in the type of their elements. Why is it then not so with Java? I read once an account where James Gosling was asked that and he replied that they were aware of the facts, but wanted a simple way for a Java method to be able to accept any kind of array (through the Object[] type). This stems from the requirement on Java to be a "blue collar language" and not get into type-theoretical exactitudes which bring their own mental baggage. Witness generics' <? super String> and Scala's covariant/contravariant position rules.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.