开发者

why does java allow this?

开发者 https://www.devze.com 2023-03-02 03:17 出处:网络
it is syntactically legal to do this:开发者_运维问答 String [] s = new String[1]; Object [] o = s;

it is syntactically legal to do this:开发者_运维问答

String [] s = new String[1];
Object [] o = s;

o[0] = new Integer(42);

but of course it will crash at runtime.

my question is: what is the point of allowing this assignment in the first place?


The problem is the assignment Object [] o = s; - I assume that's what you mean by "this".

The technical term is array covariance, and without it, you could not have code that deals with arrays generically. For example, most of the non-primitive-array methods in java.util.Arrays would be useless as you could only use them with actual Object[] instances. Obviously, this was considered more important by the designers of Java than complete type safety.

There is an alternative solution, which you see when looking at Java's generics introduced in Java 5: explicit covariance via wildcards. However, that results in considerable added complexity (see the constant stream of questions about the ? wildcard), and Java's original designers wanted to avoid complexity.


The point of allowing that kind of assignment is that disallowing it would make things like the following impossible:

ArrayList[] lists = new ArrayList[10];
lists[0] = new ArrayList();

List[] genericLists = lists;
lists[0].add("someObject");

If the compiler forbids your String -> Object case, then it would also have to forbid ArrayList -> List and any other instance of assigning from a subclass to one of its superclass types. That kind of makes a lot of the features of an object-oriented language such as Java useless. Of course, it's much more typical to do things like:

List[] lists = new List[10];
lists[0] = new ArrayList();
lists[0].add("someObject");

But regardless, the compiler can't filter out these cases without simultaneously disallowing many useful and legitimate use-cases, so it's up to the programmer to make sure that what they are doing is sane. If what you want is an Object[], then declare your variable as such. If you declare something as String[], cast it to an Object[], and then forget that what you really have is a String[], then that is simply programmer error.


It's not allowed, you get a java.lang.ArrayStoreException: java.lang.Integer when you run that code

The compiler allows it, because you're casting a String[] to Object[], which is correct. This is similar to

Integer i = new Integer(10);
Object o = i;
String s = (String) o;

The compiler doesn't complain, but you get a ClassCastExeption at runtime.


The compiler can't know (without static analysis) that o is actually a String[] and so allows the assignment even though it fails at runtime. There's nothing preventing a e.g. Integer[] to be assigned to o, it just doesn't happen.


The assignment must be allowed because the compiler cannot infer if the array will hold (or will not hold) only strings at runtime. It throws an [ArrayStoreException][1] which is checked at runtime.

Consider this:

String [] s = new String[1];
Object [] o = s;

o = new Integer[1];

o[0] = new Integer(1);

This situation is valid and runs OK. To give a more broader perspective, IMHO Arrays are a low-level leaky abstraction in Java.


Generally the compiler can't tell if o has been assigned as String[]. Consider this:

String[] s = new String[1];
Object[] o;

if (complexFunction(System.currentTimeMillis())) {
  o = s;
} else {
  o = new Integer[1];
}

o[0] = 42;

The compiler won't know at design time what type o is going to take - so it just allows the assignment.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号