2

所以我将一个 Car 对象数组写到一个文件中。然后,当我尝试在汽车变量中读回它们时,我会在语句中设置cars = (Car[])in.readObject();。但是,当我使用调试器逐步完成它时,一旦我退出 try-catch 块,汽车变量就会“取消设置”。

Car[] cars;
try {
    ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename)));
    cars = (Car[])in.readObject();
    in.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

另一方面,如果我初始化汽车变量,例如初始化为一个空数组,汽车变量在 try-catch 块之后保持设置。

Car[] cars = new Car[0];
try {
    ObjectInputStream in = new ObjectInputStream(new FileInputStream(filename)));
    cars = (Car[])in.readObject();
    in.close();
} catch (FileNotFoundException e) {
    e.printStackTrace();
} catch (IOException e) {
    e.printStackTrace();
} catch (ClassNotFoundException e) {
    e.printStackTrace();
}

那么为什么汽车变量只保留对我用 in.readObject 读取的 Car[] 的引用,前提是我事先对其进行了初始化?我不明白为什么无论我是否初始化汽车都会有任何区别......无论哪种方式,它都会在 try-catch 块中获取读取 Car[] 对象的引用。

似乎正在发生一些延迟初始化......虚拟机只是在 try catch 块中为汽车对象声明空间,因此当它退出块时它超出范围......

4

4 回答 4

4

它不会“未设置”-但您将无法在第一个示例中的块之后读取carsin code的值try/catch,因为它不是明确分配的。(如果您尝试这样做,您将得到一个编译时错误。)如果在try块的前两个语句中的任何一个中引发异常,则不会为其分配任何值。

您可以通过不只是盲目地捕获异常并在打印堆栈跟踪后继续来解决此问题:

  • 仅捕获您感兴趣的特定异常。catch (Exception e)几乎总是一个坏主意
  • 您不一定需要捕获任何东西-您的方法实际上可以处理异常吗?如果没有,只需声明它可能会被抛出。你总是可以抓住并重新抛出它。
  • 如果你真的可以处理它,也许你实际上应该在 catch 块中分配一个默认值

如果您遵循这些要点(重新抛出、让它冒泡或分配适当的值),那么变量将被确定分配,一切都会好起来的。

于 2012-10-19T13:13:19.117 回答
1

我将尝试用一个例子来解释它。以下代码不可编译:

public static void main(String[] args)
{
    String something;
    try {
        something = "123"; 
    } catch (Exception e) {

    }
    System.out.println(something);
}

另一方面,下一个片段是可编译的。但是调试器不会向您显示块something外部的值,try因为如果不初始化(上面的编译错误)引用它是不合法的。

public static void main(String[] args)
{
    String something;
    try {
        something = "123"; 
    } catch (Exception e) {

    }

    String somethingelse ="456";
    System.out.println(somethingelse);
}
于 2012-10-19T13:16:28.420 回答
0

只要到达代码中的某个点,该点超出了 var 的最后一次使用,该变量就可以在运行时合法地“取消设置”。这种优化是由 HotSpot 例行完成的,有时它可以节省大量内存,甚至可以防止OutOfMemoryError. 但是,这可能不会在调试会话中发生。

在编译时,静态分析器可以确定您的 var 的范围可以缩小到仅在 try 块内,并像在 try 内实际声明 var 一样进行编译。这将准确解释为什么您在两个代码示例之间看到不同的行为:在第二个示例中,缩小范围是不可能的,因为您在外部范围内分配。

于 2012-10-19T13:13:26.550 回答
0

在第一种情况下,您必须得到一个编译时错误Object not initialized

这是在 Java 中创建数组时发生的情况。

String[] 花色 = { "俱乐部", "钻石", "红心", "黑桃" };

在此处输入图像描述

这适用于所有对象数组。现在,在您的情况下,您已经创建了cars将引用数组的数组,您正在 try catch 块中执行此操作。

来源链接

于 2012-10-19T13:23:07.633 回答