【发布时间】:2017-08-02 10:44:25
【问题描述】:
int[] 是派生自java.lang.Object 的类型(它的子类型)。
所以应该禁止分配int[] array = new Object()(没有强制转换),因为我不能写(没有强制转换)derivedObj = baseObj(但我可以写derivedObj = (Derived) baseObj)。
为什么下面的代码可以正常编译(并在运行时工作)?如果没有像int[] ar2 = (int[]) ar1.clone(); 那样显式转换,则克隆返回的Object 类型不能隐式转换为Object 的子类型(即int[])会报错,这也可以编译并正常工作。
int[] ar1 = { 1, 2, 3, 4, 5 };
//now we assign Base class to Derived class without explicit cast
int[] ar2 = ar1.clone(); // why no compile ERR here???
System.out.println(Arrays.toString(ar2)); // output: [1, 2, 3, 4, 5]
但下面的代码将无法编译,我理解为什么:如果没有显式转换(将 int[] 视为 Object 的子类),我们无法从 Base 类转换为 Derived 类。
Object obj = new Object();
ar2 = obj; // c.ERR!! cannot convert from Object to int[]
我的猜测是这样的:clone() 在原始数组中被覆盖以返回不是 Object,而是 Object 的子类,因此 int[].clone() 返回 int[] !!! 它被覆盖的方法可以返回子类型(更专业的类型)。此外,int[] "class" 中的这个被覆盖的 clone() 也将其可见性从 protected 更改为 public(在覆盖时也允许增加可见性)。
概念证明:
int[] arr = { 1, 2, 3 };
System.out.println((arr.clone()).getClass()); // class [I
System.out.println((arr.clone()).getClass().getCanonicalName()); //int[]
更多实验:
与 Object 中的 clone() 具有相同签名的用户定义方法(参见下面的 sn-p)会产生编译错误,这与上面最顶层 sn-p 中的 clone() 不同。另请注意,在下面的 sn-p 中,方法返回 int[] 为“return arr”还是“return (Object) arr”):
public class MyTest {
static Object returns_arr_as_Object() {
int[] arr = { 1, 2, 3 };
return arr; // snippet don't change if add cast: (Object) arr
}
public static void main(String[] args) {
Object obj = returns_arr_as_Object(); // fine!
int[] myarr;
myarr = returns_arr_as_Object(); // c.ERR! can't Object -> int[]
但是如果我们将 return_arr_as_Object() 从 Object 更改为 int[],则 sn-p 可以正常编译!
附加信息:
Java 语言规范第 4.3.1 节:“数组是对象”+“The 数组类型的超类型关系与超类关系不同。 Integer[] 的直接超类型是 Number[] 根据 §4.10.3,但 Integer[] 的直接超类是 Object 根据 Integer[] 的 Class 对象(第 10.8 节)。这无关紧要 练习,因为Object也是所有数组类型的superTYPE。”
数组是协变的(与参数化的泛型不同,它是不变的),这意味着 Integer[] 是 Object[](但反之亦然,并且似乎不适用于 int[] vs Object[])
其他实验:
片段 1:
int[] ar1 = { 1, 2 };
int[] ar2 = { 10, 20 };
Object obj = ar2; // now compiler knows that obj points to int[]
ar1 = obj; // c.ERR: cannot convert from Object to int[]
片段 2:
int[] ar1 = { 1, 2 };
int[] ar2 = { 10, 20 };
Integer[] arInteger = { 10, 20 };
Object[] objArr = ar2; // c.ERR: can't from int[] to Object[]
Object obj = ar2; // COMPILES!, but useless: obj[0] is c.ERR
ar1 = obj; // c.ERR: cannot convert from Object to int[]
arInteger = obj; // c.ERR: cannot convert from Object to Integer[]
Object obj2 = arInteger;
ar1 = obj2; // c.ERR: cannot convert from Object to int[]
arInteger = obj2; // c.ERR: cannot convert from Object to Integer[]
Object[] obj2Arr = arInteger; // COMPILES FINE !!!
ar1 = obj2Arr; // c.ERR: can't convert from Object[] to int[]
arInteger = obj2Arr; // c.ERR: can't from Object[] to Integer[]
Object[] oArr = ar2; // c.ERR: cannot convert from int[] to Object[]
oArr = arInteger; // COMPILES!
System.out.println(oArr[0]); // output: 10
更多链接:cast primitive array to Object and back
附:我的编译器是 Eclipse (NEON 2)。
【问题讨论】: