簡體   English   中英

引擎蓋下的Java類構造

[英]Java class construction under the hood

考慮我們有這樣的類:

class A {
    public B b;

    public void someFunc() { // called sometime
        b = new B();
    }
}

B類的構造函數分配一些內部變量。

字段b不是線程安全的,因為B構造函數尚未完成時,另一個線程可以查看b null (在someFunc執行期間)

我的問題是:從邏輯角度看,構造函數還沒有完成怎么辦?

對我來說,這種重新排序是不可思議的。

在線程安全的上下文中,這通常是由於即時(JIT)編譯器引起的。 JIT編譯器采用Java字節碼並將其轉換為機器碼,以使其運行更快。 在翻譯過程中,它可以進行很多優化,例如內聯各種方法和構造函數。

假設B有一個這樣的構造函數:

class B {
    int x;
    B(int x) { this.x = x; }
}

內聯構造函數時,它將使用類似於以下內容的Java代碼:

b = new B(1);

並將其轉換為采用類似於以下步驟的機器代碼:

  1. 以某種方式為B對象分配空間。
  2. 將指向該內存的指針存儲在b
  3. 1存儲在bx

換句話說,與此類似的代碼(在排序方面):

b = new B();
b.x = 1;

但是我們實際上根本不調用構造函數。 我們只是分配一個B ,但是JVM在內部進行分配,然后直接分配bx 調用構造函數將涉及跳轉指令,因此內聯它要快一些。

著名的“雙重檢查鎖定已損壞”聲明中有一個例子。

常規Java編譯器也可以內聯構造函數,但是常規Java編譯器通常不執行許多優化。

對象的實例可以從構造函數中“退出”,如下所示:

public class EscapeDemo {
    static void escape(B b) {
        System.out.println(b.strA);
        System.out.println(b.strB); // still null in this example, even if field is final and initialized to non-null value.
    }

    public static void main(String[] args) {
        System.out.println(new B());
    }
}
class B {
   final String strA;
   final String strB;
    B() {
        strA = "some operations";
        EscapeDemo.escape(this);
        strB = "here";
    }
}

印刷品:

some operations
null
B@hashcode

並且以類似的方式,該引用可以轉義到將在其他線程中使用它的某些代碼。

就像安迪·吉伯特(Andy Guibert)在評論中添加的那樣:寫這樣的代碼是一種不好的做法-因為它可能是許多奇怪的錯誤的源頭,並且很難跟蹤錯誤-像這里,我們有一些不應該為null的東西,但是它為null。
而且,如果您想在創建對象實例時執行某些操作,最好創建靜態工廠方法,該方法將創建實例,然后對其進行某些操作(例如添加到某個集合/注冊表),然后將其返回。

另外,如果您包括怪異的代碼使用技巧-在字節碼中,java對象的創建與構造函數的調用是分開的,因此可以從字節碼級別創建對象,將其傳遞到某個地方,然后在其他地方調用構造函數。

但是否則,在執行右側表達式后會分配字段,因此對於代碼

b = new B(); 

調用構造函數后,字段b只能為nullB實例。 除非像我的轉義示例那樣從B構造函數內部設置該字段。

如果我正確理解您的問題。 您正在詢問是否創建對象A的實例,該實例的字段b為類型B並且在創建A時未初始化字段b ,只有其他一些對象調用someFunc() 當其他線程嘗試訪問該字段b時會發生什么?

如果是這樣,當您創建類型B的新對象時,JVM將為此對象分配一些內存,然后將返回引用,該引用將保留在字段b 如果其他線程在獲取新對象的引用之前嘗試訪問字段b ,它將返回null否則將返回對新創建對象的引用。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM