You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何Java代码输出0而非23?this逃逸引发的对象初始化问题咨询

Why does this code output 0 instead of 23? (Deep dive into this escaping & incomplete initialization)

Let's break down exactly what's happening here, starting with the code in question:

class A {
    final int finalValue;
    public A(B b) {
        super();
        b.doSomething(this); // this escapes!
        finalValue = 23;
    }
    int getTheValue() {
        return finalValue;
    }
}

class B {
    void doSomething(A a) {
        System.out.println(a.getTheValue());
    }
}

Step-by-step execution breakdown

When you create an instance of A with a B instance, here's the order of operations:

  1. The A constructor starts, first calling super() (which initializes the base Object portion of the A instance).
  2. Before we assign the intended value 23 to finalValue, we pass this—the partially initialized A object—to B.doSomething().
  3. doSomething immediately calls a.getTheValue(), which returns the current state of finalValue.
  4. Since finalValue is an int (a primitive type), its default uninitialized value is 0—that's what gets printed.
  5. Only after doSomething returns does the constructor finally assign 23 to finalValue.

The core problem: This escaping breaks initialization guarantees

This is a classic example of this escaping—when you expose a reference to an object before its constructor has finished running. Here's why this is such a critical issue:

  • Java promises that final fields are initialized exactly once and become immutable after construction completes. But this guarantee only holds if the object isn't leaked during construction.
  • The Java Memory Model (JMM) doesn't ensure that code accessing an escaped, partially initialized object will see the correct field values. Even final fields can appear to be in their default uninitialized state to code that accesses the object before the constructor finishes.
  • In multi-threaded environments, this becomes exponentially riskier: other threads might see a half-initialized object with default values, leading to unpredictable bugs that are extremely hard to debug and reproduce.

How to fix this

The fix is simple: never pass this to external methods, start threads, or make the object accessible to other code before the constructor finishes executing. A common pattern to enforce this is using a factory method instead of a public constructor:

class A {
    final int finalValue;
    // Make constructor private to force use of factory method
    private A() {
        super();
        finalValue = 23;
        // No this escape possible here
    }
    int getTheValue() {
        return finalValue;
    }
    // Factory method: create fully initialized object before exposing it
    public static A createA(B b) {
        A a = new A();
        b.doSomething(a); // Now a is fully initialized
        return a;
    }
}

With this approach, doSomething only gets access to the A instance after all its fields (including finalValue) have been properly set, so it will print 23 as expected.

内容的提问来源于stack exchange,提问作者Milan Srdić

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 07:44:19