Java:为啥我不能将数组声明为简单对象?

Posted

技术标签:

【中文标题】Java:为啥我不能将数组声明为简单对象?【英文标题】:Java : Why can't I declare an array as a simple Object?Java:为什么我不能将数组声明为简单对象? 【发布时间】:2013-01-17 20:33:57 【问题描述】:

在Java中,我可以编译

Object[] obj = new Object[1], new Object[2];

但我无法编译

Object obj = new Object(), new Object();

在第一个示例中,我声明了Objectsone-dimensional array,并为其分配了two-dimensional array。在第二个中,我声明了一个 Object 并为其分配了一个一维数组。

如果Java数组扩展Object,为什么第二个代码片段不能编译?为什么是第一个?

【问题讨论】:

相关:Passing directly an array initializer to a method parameter doesn't work. 【参考方案1】:

将数组分配给对象不是问题,但您必须像这样创建数组

Object obj = new Object[]  new Object(), new Object[2] ;

否则编译器不会知道它是一个对象数组而不是其他类型的数组。

【讨论】:

我认为这并不完全正确。我认为Object obj = new Object(), ... 返回一个数组,就像在“多指针数组”中一样,而new ... 返回一个指向new 之后的指针。所以Object obj = new Object[]...返回一个指向数组的指针,而Object obj = ...返回一个数组。 @Danyel:在 Java 中,变量实际上从不包含数组,它总是包含对数组的引用(松散地,“指针”)(与任何其他对象一样)。 @Crowder:是的,从技术上讲,它就是这样完成的,但这并不意味着它在内部也是这样完成的?我是说这就是为什么编译器在解释它时可能会遇到一些问题。这也只是假设,所以除非我们得到 JLS 的报价,否则争论几乎是毫无意义的。 (虽然...... JLS 是否提供有关它如何在内部实现/完成的信息?) @Danyel:JLS 定义了哪些变量持有,是的。它必须在内部以这种方式完成,否则语言的语义会崩溃。考虑一下:Object[] a; Object[] b; a = new Object[] new Object(), new Object() ; b = a; b[0] = null; System.out.println("a[0] is null? " + (a[0] == null)); 如果变量实际上包含 数组,那么b = a; 行必须是数组复制操作,不是吗?因此分配给b[0]a[0] 没有影响。但当然可以,因为 Java 定义 ab 持有 references。 :-) 是的,我知道。我实际上并没有怀疑/质疑这一点。对我来说,最终的问题是,如果Object[] o = ... 存储在应用程序的StackHeap 中。我想这就是我想要达到的目标。我知道最终o 将只是一个参考,而不是实际的数组。我希望你明白我的意思。【参考方案2】:

因为Array 不仅仅是Object 的子类。数组也有language-level semantics and syntax。

另外,您的第二个示例引出了一个问题:对象将在哪里存储您尝试初始化它的这两件事?您刚刚声明了一个对象,但它没有命名字段,并且缺少数组所具有的数字索引槽。

您的第一个示例可以编译,因为您已经声明了一个 Object 数组(即对象引用),并且您为其初始化该数组的元素是对象引用(对单个元素的引用)您通过new Object[1] 创建的数组)。

这也可能有所帮助:Java 并没有真正的二维数组,尽管有一些方便的语法使它看起来像它。它有(一维)数组的(一维)数组(你懂的)。

【讨论】:

Array 是 Object 的子类:docs.oracle.com/javase/7/docs/api/java/lang/reflect/Array.html @Robber:我说“不只是”。 "Array 不仅仅是 Object 的子类" => 但它是一个子类,你同意,所以你没有解释为什么这不起作用,事实上它确实起作用(见强盗的回答)。 “数组也有语言级别的语义和语法”=> 含糊地引用整个 JLS 中关于数组的一章只是恐吓的证明。 “你刚刚声明了一个对象,但它没有命名字段,并且缺少数字索引的插槽数组。” => 你还没有“声明一个对象”;你已经声明了一个 Object 类型的变量,它可以指向任何 Object 实例。无论如何,变量永远不会有字段。 @Boann:我同意 Robber 似乎比我更成功地解决了问题的相关方面,并为此向他/她 +1!最初的(预编辑)问题不太清楚,但我仍然认为 Robber 甚至从中得到了它。 谢谢,你写的大部分内容都很有意义。 @Boann:如果我能想出这样一个锋利的公式,你就明白了我想回答的问题。【参考方案3】:

问题在于,当您使用初始化程序创建数组时,编译器需要通过根据提供的类型检查元素的类型来确保初始化程序中的所有元素都具有相同的提供的类型。

也就是说,在初始化数组时总是需要提供类型信息。否则,编译器不知道如何验证数组初始化是否有效,从而给出illegal initializer error

将数组分配给对象没有问题。例如,您可以执行以下操作:

int[] arr = 1,2;
Object obj = arr;

以下代码无法编译:

Object obj = 1,2;

因为您没有明确提供编译器需要验证初始化程序中的值的元素类型。这是 Java 中数组初始化所必需的。

以下代码将编译:

Object[] obj = 1,2;

因为提供了元素的类型(即Object),编译器将根据Object类型检查12的类型(因为Integer是@的子类型,所以它成功了987654330@)。

【讨论】:

【参考方案4】:

你不能编译

Object obj = new Object(), new Object();

因为 obj 不是数组所以这样声明

Object[] obj = new Object(), new Object();

Object obj = new Object[]  new Object(), new Object() ;

在以下对话后编辑

【讨论】:

恐怕强盗的回答证明了你的错误。无论如何,感谢您提供答案。 你为什么认为我在这里错了?你能解释一下我想知道吗? @vamsilp: Object 变量可以持有对数组的引用,因为数组派生自Object。您不必声明变量Object[](尽管这样做可能会更有用)。只是在创建和初始化数组的时候,编译器需要知道它是什么类型的数组,所以才会出现 Robber 的语法。 @TJ Crowder 现在当你说 Object 变量可以保存对数组的引用并且我不必将变量声明为 Object[] 为什么我不能继续声明一个 String string=new String[ ] 新字符串(),新字符串();即使 String 也是一个对象,而这里的 string 是一个 String 变量?为什么 Object obj = new Object[] new Object(), new Object() ;工作和同样不能工作的字符串? @Student:我想我们都是对的,我们都是错的,因为我只回答了你的一个问题。我将继续编辑我的答案以包括 Robbers 版本以使其更清晰。

以上是关于Java:为啥我不能将数组声明为简单对象?的主要内容,如果未能解决你的问题,请参考以下文章

为啥不能在 Java 中将类声明为静态?

为啥我不能像行一样简单地获得一维数组?

JAVA中,子类将继承父类的所有属性和方法吗?为啥?

简单的 Python 问题:为啥我不能将变量分配给排序列表(就地)? [复制]

为啥 malloc() 和普通数组声明分配的堆栈帧大小不同?

为啥这个更复杂的查询比更简单的查询执行得更好?