Java:构造函数失败的对象会发生什么?

标签 java exception constructor null

考虑这个片段:

class Test1 {
    private static Test1 instance;
    @NonNull private final Date date1;
    @NonNull private final Date date2;

    Test1() throws Exception {

        this.date1 = new Date();

        Test1.instance = this;
        if (true) {
            throw new Exception();
        }

        this.date2 = new Date();
    }

    public void dump() {
        System.out.println("date1: " + date1);
        System.out.println("date2: " + date2);
    }

    static void test() {
        Test1 t1 = null;
        try {
            t1 = new Test1();
        } catch (Exception e) {
            e.printStackTrace();
        }
        Test1.instance.dump();
        assert t1 == null;
    }
}

Test1 的构造函数总是在将自身分配给静态字段后立即抛出异常。该字段保留对部分初始化对象的引用:date2 字段为 null 的对象,即使它被声明为 @NonNull最终

test() 函数无法直接获取生成的 t1 的引用。在 catch block 之后,t1 为空。 然而,Test1.instance 很好,调用它的 dump() 函数显示 date1 已初始化,但 date2null

这是怎么回事?为什么我可以保留对真正处于非法状态的对象的引用?

编辑 t1 为空这一事实是显而易见的(与 In Java what happens when an object fails to be instantiated? 不同)。这个问题是关于设法存储在静态字段中的对象的状态。

最佳答案

考虑以下类的字节码:

class Foo {
  public static void main(String[] args) {
    new Foo();
  }
}

字节码:

class Foo {
  Foo();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class Foo
       3: dup
       4: invokespecial #3                  // Method "<init>":()V
       7: pop
       8: return
}

从这里可以看出,新实例的创建和构造函数的调用是分开的(main 中的第 0 行和第 4 行)。

所以,即使没有完全初始化,实例也是存在的;您可以将对该实例的引用分配给另一个引用。

在实例完全初始化之前将实例分配给静态字段是不安全发布的一个示例,您应该(显然)避免这种情况。

关于Java:构造函数失败的对象会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37858328/

相关文章:

java - Netty IdleStateEvent 不会在服务器上引发 READER_IDLE

java - 在 java.util.logging 中为一个类指定具有多个处理程序的多个记录器

c# - 如何 : handle exceptions, 最佳实践

c++ - 在 C++ 中初始化位域结构的最佳方法是什么?

C++私有(private)构造类

java - ImageComponent3D 构造函数需要声明整数格式和 BufferedImage[] 数组

java - 如果单击后退按钮,如何登陆或导航到上一个 Activity

java - 按子列表中项目的值过滤列表

python - 重构长 try-except 链

java - 准确查明错误和异常的最佳方法是什么?