使用类型转换的Java数组初始化



以下代码让我感到困惑:

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;

我试图理解为什么这两个初始化彼此不同。第一个是post声明,而第二个是快捷方式。两者均声明为Object[]

我天真的理解是:

Object[] arr2 = {"a", "b", "c"}; // is a syntax sugar of
Object[] arr2 = new Object[] {"a", "b", "c"};

因此,arr2的运行时类型正是Object[],不能转换为String[]

但这里的情况变得很奇怪,因为Java数组是协变的:String[]Object[]的一个子类,而arr2正是String[],在arr2上从Object[]向后转换到String[]应该可以。

对此的任何解释都将不胜感激。

因为arr2Object[],所以没有什么可以阻止您编写

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

arr2正是String[]

不,它不是——正如你所说,它是Object[]——你的线路相当于:

Object[] arr2 = new Object[] {"a", "b", "c"};

这是一个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检查对象的实际执行时间类型:

System.out.println(arr2.getClass());

几乎正确。你的逻辑有缺陷:

arr2 is exactly a String[]

不,不是。它是一个对象数组。您刚刚将Strings添加到此数组中这一事实毫无意义。你本可以写

arr2 = {"a", new Integer(5) };

也是。

这可能会更清楚地说明为什么不允许将这样的数组强制转换为String[]。

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"};

相关内容

  • 没有找到相关文章