2013-09-16 44 views
15

Tôi có này đoạn mã sau:Tại sao các biến mẫu được khởi tạo trước khi hàm tạo được gọi là?

public abstract class UCMService{ 
    private String service;  

    protected DataMap dataMap = new DataMap(); 

    protected class DataMap extends HashMap<String,String> { 

     private static final long serialVersionUID = 4014308857539190977L; 

     public DataMap(){ 
      System.out.println("11111"); 
      put("IdcService",service); 
     } 
    } 

    public UCMService(String service){ 
     System.out.println("2222"); 
     this.service = service; 
    } 
} 

Bây giờ trong giao diện điều khiển các System.out.println của DataMap constructor được thực hiện trước khi các nhà xây dựng của UCMService.

Tôi đã tự hỏi tại sao nó đang xảy ra.

Trả lời

31

Điều này là do tại thời gian biên dịch, trình biên dịch chuyển mỗi khởi tạo nào bạn đã thực hiện tại nơi khai cho mọi constructor của lớp học của bạn. Vì vậy, các nhà xây dựng của UCMService lớp được hiệu quả tổng hợp để:

public UCMService(String service){ 
    super(); // First compiler adds a super() to chain to super class constructor 
    dataMap = new DataMap(); // Compiler moves the initialization here (right after `super()`) 
    System.out.println("2222"); 
    this.service = service; 
} 

Vì vậy, rõ ràng DataMap() constructor được thực hiện trước khi tuyên bố print của UCMService lớp. Tương tự, nếu bạn có bất kỳ hàm tạo nào khác trong lớp UCMService của bạn, việc khởi tạo sẽ được chuyển đến tất cả chúng.


Hãy xem mã byte của một lớp đơn giản:

class Demo { 
    private String str = "rohit"; 

    Demo() { 
     System.out.println("Hello"); 
    } 
} 

biên dịch lớp này, và thực hiện lệnh - javap -c Demo. Bạn sẽ thấy mã byte sau đây của nhà xây dựng:

Demo(); 
    Code: 
     0: aload_0 
     1: invokespecial #1 // Method java/lang/Object."<init>":()V 
     4: aload_0 
     5: ldc   #2 // String rohit 
     7: putfield  #3 // Field str:Ljava/lang/String; 
     10: getstatic  #4 // Field java/lang/System.out:Ljava/io/PrintStream; 
     13: ldc   #5 // String Hello 
     15: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     18: return 

Bạn có thể xem hướng dẫn putfield tại dòng 7, khởi lĩnh vực str để "rohit", đó là trước khi print statement (hướng dẫn tại dòng 15)

+0

+1 đây là một câu trả lời hay :) – nachokk

+0

Ahh ... Đây là siêu rõ ràng :) –

+0

giải thích tuyệt vời. cảm ơn rất nhiều Rohit. –

13

Câu trả lời ngắn:
Do thông số nói như vậy.

Câu trả lời dài:
Sẽ rất lạ khi người xây dựng không thể sử dụng các trường được khởi tạo nội tuyến.

Bạn muốn để có thể viết

SomeService myService = new SomeService(); 
public MyConstructor() { 
    someService.doSomething(); 
} 
+0

Chờ, vì vậy một số người bảo tôi không làm việc trong nhà xây dựng. Tôi lấy điều này để có nghĩa là, chỉ gán các biến trong constructor. Liệu someService.doSomething() có tính là công việc không? – Kammeot

+1

Nếu doSomething() thực sự làm điều gì đó, thì có - đó là công việc. – nos

+0

@ nos và nếu 'doSomething()' không làm điều gì đó, thì nó sẽ được đổi tên thành một cái gì đó mô tả hơn. – AJMansfield