为什么超类的实例可以放入子类数组?

Ern*_*usc 6 java inheritance

我们假设我们有两个类:

class X { }

class Y extends X { }
Run Code Online (Sandbox Code Playgroud)

在main函数中创建一个数组:

Y[] yArr = new Y[3] // created Y's class objects array

X[] xArr = yArr;

xArr[0]= new X() // VALID. WHY?
Run Code Online (Sandbox Code Playgroud)

怎么会这样??因为xArr引用Y[]对象并且为了我的理解它不能创建X对象.

rge*_*man 9

Java编译器允许这样做,因为在Java数组中是协变的.即,可以说:

Superclass[] arr = new Subclass[3];
Run Code Online (Sandbox Code Playgroud)

这允许你的代码xArr[0]= new X();编译.但是,JVM将在运行时捕获此错误并抛出ArrayStoreException.它在运行时知道它确实是一个Y[3],因此无法存储X.

JLS,4.10.3节,规定阵列类型的协方差:

以下规则定义了数组类型之间的直接超类型关系:

  • 如果S和T都是引用类型,则S []> 1 T [] iff S> 1 T.

  • 对象> 1对象[]

  • Cloneable> 1 Object []

  • java.io.Serializable> 1对象[]

  • 如果P是基本类型,则:

    • 对象> 1 P []

    • 可克隆> 1 P []

    • java.io.Serializable> 1 P []

这与仿制药相反,仿制药不是协变的 - 它们是不变的.即

ArrayList<Superclass> list = new ArrayList<Subclass>();  // doesn't compile.
Run Code Online (Sandbox Code Playgroud)