2014-04-15 23 views
37

Vì vậy, tôi đang cố gắng kết hợp quá trình khởi tạo và khởi tạo trong JVM nhưng JLS là một chút ngớ ngẩn về một vài chi tiết, vì vậy nếu có ai đó lo lắng thanh toán bù trừ một số chi tiết, nó sẽ được apreciated . Đây là những gì tôi đã có thể tìm ra cho đến nay.Thứ tự khởi tạo và khởi tạo Java

Khởi

  1. Đệ quy Khởi tạo biến thức tĩnh của lớp và nó giao diện mà là hằng số thời gian biên dịch.

  2. Thoát khỏi các khối tĩnh xử lý đệ quy và các trường tĩnh theo thứ tự văn bản.

õ

  1. Đệ quy Khởi tạo các biến Ví dụ cuối cùng của lớp đó là hằng số thời gian biên dịch.

  2. Thoát khỏi quá trình xử lý đệ quy các khối không tĩnh và trường mẫu trong thứ tự văn bản để thêm chúng vào các hàm tạo khi nó trả về.


Được rồi, vì vậy bây giờ cho các câu hỏi.

  1. là các giao diện được xử lý theo thứ tự khai báo?

  2. là các giao diện được xử lý trong ngăn xếp đệ quy riêng biệt?

    a) nếu có, giao diện có được xử lý trước hoặc sau siêu lớp không?

    b) nếu có, tôi có đúng khi suy luận rằng một hoặc những người khác (Giao diện hoặc Siêu lớp) nhận các trường liên tục không biên dịch được khởi tạo trước các hằng số biên dịch khác.

  3. Cuộc gọi vai trò nào đối với trình tạo cấu trúc không cố định() trong quá trình này?

  4. Tôi có nhầm lẫn với bất kỳ kết luận nào của mình không?

  5. Tôi có thiếu bất kỳ chi tiết chính nào khác không?

+0

Giao diện không có gì để khởi tạo. Trừ khi bạn đang sử dụng từ ngữ trong một thời trang khác với tôi đã từng sử dụng. –

+1

@BobDalgleish Giao diện có thể có các trường cuối cùng tĩnh công cộng. Nếu các trường đó là đối tượng có bộ khởi tạo (ví dụ: 'public static final ArrayList someStrings = new ArrayList <>();') thì đó sẽ là một phần của quá trình khởi tạo. – hexafraction

Trả lời

38

Điều quan trọng là phải phân biệt giữa khởi tạo lớp và khởi tạo đối tượng.

Lớp khởi

Một lớp học hoặc giao diện được khởi tạo khi first access, bằng cách gán các thời gian biên dịch các lĩnh vực liên tục, sau đó đệ quy khởi tạo lớp cha (nếu chưa được khởi tạo), sau đó xử lý initializers tĩnh (trong đó bao gồm các khởi tạo cho các trường tĩnh không biên dịch hằng số thời gian).

Như bạn đã nhận thấy, việc khởi tạo một lớp không tự khởi động kích hoạt các giao diện mà nó thực hiện. Giao diện do đó được khởi tạo khi chúng được truy cập lần đầu tiên, thường là bằng cách đọc một trường không phải là hằng số thời gian biên dịch. Truy cập này có thể xảy ra trong quá trình đánh giá bộ khởi tạo, gây khởi tạo đệ quy.

Nó cũng đáng chú ý khởi tạo mà không được kích hoạt bằng cách truy cập các lĩnh vực mà là hằng số thời gian biên dịch, vì đây là những đánh giá ở compile time:

Một tham chiếu đến một lĩnh vực mà là một biến đổi (§4.12. 4) phải được giải quyết tại thời gian biên dịch với giá trị V được biểu thị bằng bộ khởi tạo biến không đổi.

Nếu trường như vậy là tĩnh, thì không có tham chiếu đến trường nên có trong mã trong tệp nhị phân, bao gồm lớp hoặc giao diện khai báo trường. Trường như vậy phải luôn luôn xuất hiện để được khởi tạo (§12.4.2); giá trị ban đầu mặc định cho trường (nếu khác với V) không bao giờ được quan sát.

Nếu trường như vậy không tĩnh, thì không có tham chiếu đến trường sẽ có trong mã trong tệp nhị phân, ngoại trừ trong lớp có chứa trường. (Nó sẽ là một lớp chứ không phải là một giao diện, vì một giao diện chỉ có các trường tĩnh.) Lớp nên có mã để đặt giá trị của trường thành V trong quá trình tạo cá thể (§12.5).

Object Khởi

Một đối tượng được khởi tạo whenever a new object is created, thường bằng cách đánh giá của một biểu thức tạo lớp ví dụ. Này diễn ra như sau:

  1. Gán các đối số cho các nhà xây dựng để biến tham số mới được tạo ra cho gọi constructor này.

  2. Nếu hàm khởi tạo này bắt đầu với lời gọi hàm khởi tạo (§8.8.7.1) của một hàm tạo khác trong cùng một lớp (sử dụng), sau đó đánh giá các đối số và quy trình mà hàm tạo yêu cầu đệ quy bằng 5 bước này. Nếu lời gọi hàm khởi tạo đó hoàn thành đột ngột, thì thủ tục này hoàn thành đột ngột vì cùng một lý do; nếu không, hãy tiếp tục với bước 5.

  3. Hàm khởi tạo này không bắt đầu bằng cách khởi tạo hàm tạo rõ ràng của một hàm tạo khác trong cùng một lớp (sử dụng). Nếu hàm khởi tạo này là cho một lớp khác với Object, thì hàm khởi tạo này sẽ bắt đầu với một lời gọi rõ ràng hoặc tiềm ẩn của một hàm tạo siêu lớp (sử dụng siêu). Đánh giá các đối số và quy trình mà hàm tạo của lớp bậc trên gọi đệ quy bằng cách sử dụng cùng năm bước này. Nếu lời gọi hàm khởi tạo đó hoàn thành đột ngột, thì thủ tục này hoàn thành đột ngột vì cùng một lý do. Nếu không, tiếp tục với bước 4.

  4. Execute initializers dụ và ví dụ initializers biến cho lớp này, gán các giá trị của initializers biến ví dụ để các biến tương ứng, theo thứ tự từ trái sang bên phải, trong đó họ xuất hiện textually trong mã nguồn cho lớp. Nếu việc thực hiện bất kỳ trình khởi tạo nào trong số các trình khởi tạo này dẫn đến một ngoại lệ, thì không có trình khởi tạo thêm nào được xử lý và thủ tục này hoàn thành đột ngột với cùng một ngoại lệ đó. Nếu không, tiếp tục với bước 5.

  5. Thực hiện phần còn lại của phần thân của hàm tạo này. Nếu việc thực thi đó hoàn thành đột ngột, thì thủ tục này hoàn thành đột ngột vì cùng một lý do. Nếu không, thủ tục này sẽ hoàn thành bình thường.

Như chúng ta có thể thấy trong bước 3, sự hiện diện của một cuộc gọi rõ ràng để các nhà xây dựng siêu đơn giản thay đổi mà siêu lớp constructor được gọi.

1

Sau đây là ví dụ in thứ tự của từng bước trong quá trình tạo đối tượng.

InstanceCreateStepTest.java:

import javax.annotation.PostConstruct; 

/** 
* Test steps of instance creation. 
* 
* @author eric 
* @date Jan 7, 2018 3:31:12 AM 
*/ 
public class InstanceCreateStepTest { 
    public static void main(String[] args) { 
     new Sub().hello(); 
     System.out.printf("%s\n", "------------"); 
     new Sub().hello(); 
    } 
} 

class Base { 
    static { 
     System.out.printf("%s - %s - %s\n", "base", "static", "block"); 
    } 
    { 
     System.out.printf("%s - %s - %s\n", "base", "instance", "block"); 
    } 

    public Base() { 
     System.out.printf("%s - %s\n", "base", "constructor"); 
    } 

    @PostConstruct 
    public void init() { 
     System.out.printf("%s - %s\n", "base", "PostConstruct"); 
    } 

    public void hello() { 
     System.out.printf("%s - %s\n", "base", "method"); 
    } 
} 

class Sub extends Base { 
    static { 
     System.out.printf("%s - %s - %s\n", "sub", "static", "block"); 
    } 
    { 
     System.out.printf("%s - %s - %s\n", "sub", "instance", "block"); 
    } 

    public Sub() { 
     System.out.printf("%s - %s\n", "sub", "constructor"); 
    } 

    @PostConstruct 
    public void init() { 
     System.out.printf("%s - %s\n", "sub", "PostConstruct"); 
    } 

    @Override 
    public void hello() { 
     // super.hello(); 
     System.out.printf("%s - %s\n", "sub", "method"); 
    } 
} 

Thực hiện:

Chỉ cần gọi phương thức main, và sau đó kiểm tra đầu ra.

Mẹo:

  • Các phương pháp đánh dấu bằng @PostConstruct sẽ không được áp dụng, trừ khi bạn gọi nó bên trong một số container, như Spring-boot, vì nó phụ thuộc vào những thùng chứa để thực hiện chú thích như @PostConstruct.
Các vấn đề liên quan