简体   繁体   中英

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;

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

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, Object s can undergo casting conversion to String s:

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."

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM