java - int[] arr2 = arr1.clone() 编译时不会将 RHS (Object) 转换为 (int[])。为什么 derivedObj = baseObj 允许不强制转换为 Derived(即 int[])?

标签 java arrays object

int[] 是派生自 java.lang.Object 的类型(它的子类型)。 因此,出于与我无法编写(不强制转换)derivedObj = baseObj(但我可以写 derivedObj = (Derived) baseObj).

为什么下面的代码可以正常编译(并在运行时运行)?它应该给出错误,克隆返回的 Object 类型不能隐式转换为 Object 的子类型(即 int[]),而不像这样显式转换int[] ar2 = (int[]) ar1.clone();,它也可以编译并正常工作。

    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 的子类)。

Object obj = new Object();
ar2 = obj; // c.ERR!! cannot convert from Object to int[]

我的猜测是这样的:clone() 在原始数组中被覆盖,返回的不是 Object,而是 Object 的子类,所以 int[].clone() 返回 int[] !!! 它覆盖方法有可能返回子类型(更专业的类型)。此外,这个在 int[]“类”中被覆盖的 clone() 的可见性也从 protected 变为公开(在覆盖时也允许增加可见性)。

概念验证:

int[] arr = { 1, 2, 3 };        
System.out.println((arr.clone()).getClass()); // class [I
System.out.println((arr.clone()).getClass().getCanonicalName()); //int[]

更多实验:

与 Object 中的 clone() 具有相同签名的用户定义方法(参见下面的代码片段)会产生编译错误,这与上面最上面代码片段中的 clone() 不同。另请注意,在下面的代码片段中,方法返回 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[],代码片段编译正常!

附加信息:

§4.3.1 of Java Language Specification: "arrays are objects" + "The supertype relation for array types is not the same as the superclass relation. The direct supertype of Integer[] is Number[] according to §4.10.3, but the direct superclass of Integer[] is Object according to the Class object for Integer[] (§10.8). This does not matter in practice, because Object is also a superTYPE of all array types."

数组是协变的(不同于不变的参数化泛型),这意味着 Integer[] 是 Object[](但反之亦然,似乎它不适用于 int[] 与 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)。

最佳答案

编译器知道ar1.clone() 是一个int[]。因此,它可以毫无问题地进行分配。

另一方面,编译器不知道obj 是否是int[]。因此,它不允许在没有显式强制转换的情况下进行赋值(这是你告诉编译器你知道你在做什么,这是故意的。)

关于java - int[] arr2 = arr1.clone() 编译时不会将 RHS (Object) 转换为 (int[])。为什么 derivedObj = baseObj 允许不强制转换为 Derived(即 int[])?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42746325/

相关文章:

java - 如何在Java客户端使用通过serviceAccounts.keys.create API生成的Google云平台服务帐户 key ?

java - java中将对象赋值给变量

javascript - 使用对象正确替换全局变量

java - 生成 SOAP 请求

java - 到达 N 步的方法数

java - 如何在给定的包中找到带注释的方法?

python - 仅沿最后两个维度获取矩阵乘积的单个操作

javascript - 如何将值数组映射到对象数组

javascript - 如何在javascript中访问这个数组

javascript - 过滤嵌套对象并保留父对象