以下代码让我感到困惑:
Object[] arr1 = new String[]{"a", "b", "c"};
Object[] arr2 = {"a", "b", "c"};
String[] a = (String[]) arr1; // ok
String[] b = (String[]) arr2; // ClassCastException
System.out.println(arr1.getClass().getName()); // [Ljava.lang.String;
System.out.println(arr2.getClass().getName()); // [Ljava.lang.Object;
我试图理解为什么两个初始化彼此不同。第一个是帖子声明,第二个是捷径。这两个都被声明为Object[]
我天真的理解是:
Object[] arr2 = {"a", "b", "c"}; // is a syntax sugar of
Object[] arr2 = new Object[] {"a", "b", "c"};
因此arr2
的运行时类型正好是Object[]
,无法转换为String[]
。
但是这里的事情很奇怪,因为Java Array是协变的:
String[]
是Object[]
的子类,而arr2
只是String[]
,从Object[]
向String[]
转回arr2
工作
对此的任何解释都表示高度赞赏。
答案 0 :(得分:6)
因为arr2
是Object[]
,所以没有什么能阻止你写作
arr2[0] = new Object();
在你的演员阵容之前,无论如何演员阵容将不再有意义。
由于初始化程序语法的工作方式,请注意以下内容:
Object x = {"a", "b"}; // error: illegal initializer for Object
Object[] a = {"a", "b"}; //a has class [Ljava.lang.Object;
String[] b = {"a", "b"}; //b has class [Ljava.lang.String;
编译器根据您的声明确定您的阵列是Object[]
还是String[]
。
答案 1 :(得分:5)
arr2正是一个String []
不,它不是 - 如你所说的那样Object[]
- 你的行相当于:
Object[] arr2 = new Object[] {"a", "b", "c"};
发生<{1}} 发生以包含目前所有字符串引用的元素......但您也可以写:
Object[]
如果您对arr2[0] = new Object(); // Fine, because arr2 is an Object[]
做了同样的事情,那么您将获得例外:
arr1
您当然可以使用arr1[0] = new Object(); // Fine at compile time, will throw an exception
检查对象的实际执行时类型:
getClass
答案 2 :(得分:3)
几乎正确。你的逻辑存在缺陷:
arr2 is exactly a String[]
不,不是。它是一个对象数组。您刚刚将Strings添加到此数组中这一事实毫无意义。你可以写
arr2 = {"a", new Integer(5) };
太。
可能会更清楚,为什么不允许你将这样的数组转换为String []。
答案 3 :(得分:1)
Object[] arr2 = {"a", "b", "c"};
在这种情况下,您声明的数组等于
Object[] arr2 = new Object[] {"a", "b", "c"};
因此,arr2中的元素可以是任何类型的Object
。在行
String[] b = (String[]) arr2; // ClassCastException
因为您正在尝试将整个Object[]
投射到String[]
。
在第一个中你明确告诉所有对象是字符串
Object[] arr1 = new String[]{"a", "b", "c"};