3

如果构造函数以异常结束,那么创建的对象是否与正常对象完全相同?

class A {

    static A o;

    A() throws Exception {
        o=this;
        throw new Exception();
    }

    void f() { System.out.println("f(): entry."); };

    static public void main(String[]args ) {
        try {
         A o =new A();
        }
        catch (Exception e) {
              System.out.println("Exception: " + e);
        }

        A.o.f(); // Is it safe to use this object?
       }
}

这编译并运行,这个程序的输出是:

Exception: java.lang.Exception
f(): entry.
4

2 回答 2

3

如果你捕捉到异常,构造的对象永远不会传回给调用者,调用者的结果变量也不会被设置。但是,理论上,静态变量会被设置,我看不出它无法访问的任何原因。

this但是请注意,在调用构造函数之前,方法验证不允许您存储super,因此这不是进入其他受保护对象的“后门”。

由于它是您的对象,因此“安全”取决于您。

[更详细一点:当您的构造函数的编译版本被输入时,“原始”Java 对象被完全构造——系统不需要额外的工作来使其有效。但是super,尚未调用构造函数,由您来显式super调用或让编译器默认插入super调用(如果您没有显式调用,它将在方法的开头执行此操作)。JVM 中的“字节码验证器”对调用构造函数之前在构造函数中可能发生的事情有一些非常严格的规则super,并且存储this到静态将是一个明确的禁忌——你会得到一个 VerifyError。]

于 2012-05-18T03:21:30.857 回答
2
 A.o.f(); // Is it safe to use this object?

它是一个常规的 java 对象,它将像任何其他 Java 对象一样响应方法调用。就 Java 语言而言,这不是未定义行为的来源。

这并不意味着它可以安全使用。许多类的安全性取决于它们维护重要不变量的能力,而在构造或关键操作期间抛出的意外异常通常意味着这些不变量不成立,因此使用起来不安全。

考虑如果你继承 A 会发生什么

public class S extends A {
  boolean dirty;

  S() throws Exception {
    // Do work to maintain important security invariants.
    dirty = true;
  }

  void foo() {
    if (dirty) {
      System.out.println("clean");
      dirty = false;
    }
    System.out.println("foo");
  }

  public static void main(String... argv) {
    try {
      new S();
    } catch (Exception ex) {}
    // Now A.o is an instance of S, but S's constructor
    // was never called.
    S s = (S) A.o;  // works.
    s.foo();  // Never prints clean before printing foo.
  }
}
于 2012-05-18T03:12:43.207 回答