Java 如何将对象数组强制转换为整数数组

Java 如何将对象数组强制转换为整数数组,java,Java,这是一个有点做作的例子来解释我遇到的情况,但基本上,我有一个对象数组,实际上包含整数数组,我正试图将其转换为整数数组。下面是模拟这种情况的代码片段: Object[] foo = new Object[3]; foo[0] = new int[] { 1, 2, 3 }; foo[1] = new int[] { 4, 5, 6 }; foo[2] = new int[] { 7, 8, 9 }; int[][] bar = (int[][]) foo; 当我尝试这样做时,我在线程“main”

这是一个有点做作的例子来解释我遇到的情况,但基本上,我有一个对象数组,实际上包含整数数组,我正试图将其转换为整数数组。下面是模拟这种情况的代码片段:

Object[] foo = new Object[3];
foo[0] = new int[] { 1, 2, 3 };
foo[1] = new int[] { 4, 5, 6 };
foo[2] = new int[] { 7, 8, 9 };
int[][] bar = (int[][]) foo;
当我尝试这样做时,我在线程“main”java.lang.ClassCastException:[Ljava.lang.Object;无法转换为[[I


有没有一种方法可以在不复制数组的情况下执行此操作(我可能不想执行此操作,因为
foo
在生产中将非常大)如果不是,为什么不呢?

因为
foo
是对象数组,它意味着它可以包含任何东西,而不仅仅是整数数组,所以编译器不能允许您将它转换为整数数组,因为您知道它在里面


如果您想使用
int[]bar
reference,则必须创建单独的
int[3][]
首先数组,然后将
foo
的内容复制到该数组。

您不能通过强制转换来更改Java对象的固有类型。这包括数组。对象的类型在分配对象时是固定的,不能更改

因此,将
对象[]
强制转换为
int[][]
将永远不起作用

在这种情况下,虽然
int[][]
Object[]
的子类型,但这不足以在运行时允许类型转换。JLS()中的实际规则如下:

“以下是检查对象的运行时类型R的赋值是否与类型T兼容的算法,类型T是在强制转换运算符中命名的类型的擦除(§4.6)。如果引发运行时异常,则它是一个
ClassCastException

如果R是表示数组类型RC[]的类,即RC类型的组件数组:

  • 如果T是TC[]类型的数组,即TC类型的组件数组,则会引发运行时异常,除非以下情况之一为真:

    • “TC和RC是相同的基元类型。”

    • “TC和RC是引用类型,可以通过递归应用这些运行时规则将类型RC转换为TC进行转换。”

在这种情况下,TC是
int[]
,RC是
Object
,而
Object
不能强制转换为
int[]
。因此会出现异常

为了说明为什么必须发生这种情况,请考虑这个(假设的)例子:

假设可以“强制”转换
foo
的值,那么
神秘
变量应该指向什么?它不能是
int[]
,因为我们没有分配它。它不能是
对象
实例,因为这样会破坏静态类型

事实上,“强制转换”必须是非法的,否则Java的静态类型系统就会崩溃


你的例子和我的例子之间的区别在于foo实际上不是一个整数数组的数组,而在我的例子中它是。为什么VM不能看到对象的“实际”类型

关键是,静态类型化(主要)是由编译器而不是JVM强制执行的。虽然JVM(理论上)可以在运行时判断出类型是正常的(如果不是,则抛出异常),但编译器不能这样做,因为它无法确定通常的类型是什么


不幸的是,我并不是亲自创建数组。我是从另一个函数获得它的,
Object[]
而不是
int[][]
,据我所知,这是我无法控制的某些序列化的副作用

不幸的是,您必须复制数组…或将其用作
对象[]
,并将元素强制转换为
int[]
,才能使用它们;例如

Object[] foo = new Object[3];
foo[0] = new int[] { 1, 2, 3 };
foo[1] = new int[] { 4, 5, 6 };
foo[2] = new int[] { 7, 8, 9 };
...
int nine = ((int[]) (foo[2]))[2];
Java中没有“相信我,它实际上是一个
int[][]
”选项


如果这是序列化的副作用,那么序列化在某种意义上被破坏了。当然,标准Java对象序列化协议/实现不会发生这种情况。这会保留对象的类型…除非您在
readObject
/
writeObject
方法中显式重写它们,等等ra.

您需要在访问每个对象时对其进行强制转换

    Object[] foo = new Object[3];
    foo[0] = new int[] { 1, 2, 3 };
    foo[1] = new int[] { 4, 5, 6 };
    foo[2] = new int[] { 7, 8, 9 };
    int[] foo2 = (int[])foo[2];
    System.out.println("foo[2,2]="+((int[])foo[2])[2]);
如果您认为内容可能是非整数,那么还应该将其包装在
try…catch


编辑:简化代码。

只是想对这一点有一个明确的理解,显然你对它的工作方式是正确的——你的例子和我的例子之间的区别在于,foo实际上不是一个整数数组数组,而在我的例子中是。为什么虚拟机看不到“实际的”对象的类型?虽然正确,但这并不能解决OP的问题。解决方案是访问
int[]
,正如我谦恭地提交我的答案所做的那样:-)@和Y256铸造肯定会起作用,但我实际上也很好奇为什么这不起作用,所以这非常有用。@和Y256-不。正确的答案是这样做:
对象[]foo=new int[3][];
…并摆脱类型转换。@arshajii-关于子类型,您是正确的,但事实证明,失败的真正原因(根据JLS)根本不涉及这一点。(事实上,子类型解释了为什么这不是编译时错误!)我已相应地更正了我的答案。请尝试一下,谢谢,但最初的目标是不抄袭。
    Object[] foo = new Object[3];
    foo[0] = new int[] { 1, 2, 3 };
    foo[1] = new int[] { 4, 5, 6 };
    foo[2] = new int[] { 7, 8, 9 };
    int[] foo2 = (int[])foo[2];
    System.out.println("foo[2,2]="+((int[])foo[2])[2]);