对未完全构造的Java对象的回调可以明确定义吗?

问题描述 投票:0回答:1

如果类

T
的构造函数将
this
作为参数传递给某个方法
foo
,并且
foo
立即对
T
对象(尚未完成执行其构造函数)执行回调,事情显然可能会出错,但是如果我确保
foo
访问的任何字段都已初始化怎么办?

为了清楚地说明我在说什么,这里有一个确实出错的例子:

public class T {
    // Class that accesses T, which could be defined somewhere outside
    // rather than nested here.
    static class FortyTwoChecker {
        void foo(T t) {
            System.out.println("Fourty-two is: "+t.get42());
        }
    }

    // Fields set in constructor.
    private final int fortyTwo;

    // Callback method that accesses (and might also modify, in some other case)
    // fields set in constructor.
    int get42() { return fortyTwo; }

    T(FortyTwoChecker checker) {
        checker.foo(this);  // goes wrong!
        fortyTwo = 42;
    }
}

当构造

T
对象时,会打印
Fourty-two is: 0
,因为
foo
在设置
fortyTwo
之前被调用。但如果我交换
T
构造函数中的两个语句,输出将是预期的
Fourty-two is: 42
。我的问题是:我能确定这种代码总是按预期工作吗?也就是说,是否可以保证编译器/VM 不会扰乱顺序执行顺序,并且不会仅仅因为调用了不完整构造对象的方法而出现错误?

我预计如果回调是从另一个线程进行的,这可能很难回答,但如果所有事情都发生在同一个线程中,我至少可以确定吗?

(显然,最好确保在

T
对象完全构造完成之前不进行回调——并且不必担心——但在让我思考这一点的用例中,这会引发其他问题。 )

java constructor callback
1个回答
0
投票

你的错误在于用对象来思考,当你必须用属性来思考时,让我们举个例子来说明为什么会这样:

class Cat {
   int age;
   String name;
   public Cat() {}
   // setters and getters
}

class Main {
   public Main() {
      Cat black = new Cat();
      black.setAge( 10 );
      Cat white = new Cat();
      white.setAge( black.getAge() ); // work!
      white.setName( black.getName() ); // not work!
   }
}

正如您在示例中看到的,每个属性的使用都是独立的,我可以实例化“age”并使用它,而无需实例化“name”,因此该语言无法制定如何使用它的规则实例化一个对象。

© www.soinside.com 2019 - 2024. All rights reserved.