luke657
luke657

Reputation: 835

Casting arrays of a supertype to a subtype

Is there a particular reason why this results in runtime exception instead of compile-time error in Java?

Object[] objects = new Object[10];
String[] strings = (String[])objects;

Upvotes: 3

Views: 2307

Answers (3)

Matt Ball
Matt Ball

Reputation: 359786

Because this is the compile-time behavior defined by the language specification. The short version is that an Object[] can be cast to a String[] without generating a compile-time error because an Object can be cast to a String without generating a compile-time error.


The long answer is just me quoting the JLS. From the Java Language Specification § 5.5.1. Reference Type Casting:

Given a compile-time reference type S (source) and a compile-time reference type T (target), a casting conversion exists from S to T if no compile-time errors occur due to the following rules.
...
If S is an array type SC[], that is, an array of components of type SC:
...

  • If T is an array type TC[], that is, an array of components of type TC, then a compile-time error occurs unless one of the following is true:
    • TC and SC are the same primitive type.
    • TC and SC are reference types and type SC can undergo casting conversion to TC.

By a preceding rule in that same section on casting, Objects can undergo casting conversion to Strings:

If S is a class type:

  • If T is a class type, then either |S| <: |T|, or |T| <: |S|. Otherwise, a compile-time error occurs.

Just in case you were wondering:

An expression of a reference type may undergo casting conversion to another reference type if no compile-time error occurs given the rules in §5.5.1.


Note that the JLS uses |T| to denote the erasure of type T and also that S :> T indicates that the supertype relation holds between S and T. Therefore "|S| <: |T|, or |T| <: |S|" can be read as "the erasure of S is either a subtype, the same type, or a supertype of T."

Upvotes: 2

Patricia Shanahan
Patricia Shanahan

Reputation: 26185

The check has to be done at run time because of this case:

public class Test {
  public static void main(String[] args){
    String[] stringsBase = {"aaa", "bbb", "ccc"};
    Object[] objects = stringsBase;
    String[] strings = (String[])objects;
    System.out.println(strings[1]);
  }
}

This is a valid, working program. Without doing flow analysis, the compiler does not know whether objects references an array that was created as Object[], or one that was created as, in this case, a String[].

Upvotes: 5

torquestomp
torquestomp

Reputation: 3334

Casting is a fundamentally unsafe feature that Java provides for flexibility purposes. That code generates "unchecked" warnings if your compiler settings are tuned correctly.

Upvotes: 0

Related Questions