85

Chúng ta có thể đặt mã trong một hàm tạo hoặc một phương thức hoặc một khối khởi tạo. Việc sử dụng khối khởi tạo là gì? Có cần thiết rằng mọi chương trình java phải có nó?

|
161

Trước hết, có hai loại khối khởi tạo :

  • khối khởi tạo cá thể , và
  • khối khởi tạo tĩnh .

Mã này sẽ minh họa việc sử dụng chúng và theo thứ tự chúng được thực thi:

public class Test {

    static int staticVariable;
    int nonStaticVariable;        

    // Static initialization block:
    // Runs once (when the class is initialized)
    static {
        System.out.println("Static initalization.");
        staticVariable = 5;
    }

    // Instance initialization block:
    // Runs each time you instantiate an object
    {
        System.out.println("Instance initialization.");
        nonStaticVariable = 7;
    }

    public Test() {
        System.out.println("Constructor.");
    }

    public static void main(String[] args) {
        new Test();
        new Test();
    }
}

Bản in:

Static initalization.
Instance initialization.
Constructor.
Instance initialization.
Constructor.

Các khối itialization là hữu ích nếu bạn muốn có một số mã chạy bất kể hàm tạo nào được sử dụng hoặc nếu bạn muốn thực hiện một số khởi tạo cá thể cho các lớp ẩn danh.

|
  • 1

    Tại thời điểm này, có vẻ như chúng được thực hiện theo thứ tự xuất hiện trong mã. Ví dụ có thể được cải thiện theo cách thứ tự trong mã khác với thứ tự thực hiện thực tế. Ngoài ra: có thể có một số khối khởi tạo và sau đó chúng được thực hiện theo thứ tự xuất hiện (nhưng vẫn trước hàm tạo).

    – Lý Ðức Toàn 11:39:19 02/12/2014
  • 1

    @Pacerier Vì vậy, bạn có thể có mã chung khi có nhiều hàm tạo mà không phải sử dụng một init()phương thức (mà ai đó đang cập nhật lớp có thể quên gọi nó)

    – Thành Xuân Nguyễn 10:28:48 19/08/2016
  • 1

    @Thomas wellerif thực thi của nó trước khi xây dựng như thế nào đến nó cho phép thistừ khóa inisde dụ khởi tạo khối. thislà đối tượng lớp curernt và nó sẽ được xây dựng đầy đủ sau khi kết thúc cuộc gọi constructor phải không?

    – Tạ Hương Liên 09:59:16 18/06/2018
88

muốn thêm vào câu trả lời của @ aioobe

Trình tự thực hiện:

  1. khối khởi tạo tĩnh của siêu lớp

  2. khối khởi tạo tĩnh của lớp

  3. khối khởi tạo cá thể của siêu lớp

  4. nhà xây dựng của siêu lớp

  5. khối khởi tạo cá thể của lớp

  6. người xây dựng của lớp.

Một vài điểm cần lưu ý (điểm 1 là nhắc lại câu trả lời của @ aioobe):

  1. Mã trong khối khởi tạo tĩnh sẽ được thực thi tại thời gian tải lớp (và có, điều đó chỉ có nghĩa là một lần cho mỗi lần tải lớp), trước khi bất kỳ trường hợp nào của lớp được xây dựng và trước khi bất kỳ phương thức tĩnh nào được gọi.

  2. Khối khởi tạo cá thể thực sự được trình biên dịch Java sao chép vào mọi hàm tạo mà lớp có. Vì vậy, mỗi khi mã trong khối khởi tạo cá thể được thực thi chính xác trước mã trong hàm tạo.

|
6

câu trả lời hay bởi aioobe thêm vài điểm

public class StaticTest extends parent {
    static {
        System.out.println("inside satic block");
    }

    StaticTest() {
        System.out.println("inside constructor of child");
    }

    {
        System.out.println("inside initialization block");
    }

    public static void main(String[] args) {
        new StaticTest();
        new StaticTest();
        System.out.println("inside main");
    }
}

class parent {
    static {
        System.out.println("inside parent Static block");
    }
    {
        System.out.println("inside parent initialisation block");
    }

    parent() {
        System.out.println("inside parent constructor");
    }
}

cái này cho

inside parent Static block
inside satic block
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside parent initialisation block
inside parent constructor
inside initialization block
inside constructor of child
inside main

Nó giống như nói rõ ràng nhưng có vẻ rõ ràng hơn một chút.

|
3

Mã mẫu, được phê duyệt là một câu trả lời ở đây là chính xác, nhưng tôi không đồng ý với nó. Nó không hiển thị những gì đang xảy ra và tôi sẽ cho bạn thấy một ví dụ tốt để hiểu cách thức hoạt động của JVM:

package test;

    class A {
        A() {
            print();
        }

        void print() {
            System.out.println("A");
        }
    }

    class B extends A {
        static int staticVariable2 = 123456;
        static int staticVariable;

        static
        {
            System.out.println(staticVariable2);
            System.out.println("Static Initialization block");
            staticVariable = Math.round(3.5f);
        }

        int instanceVariable;

        {
            System.out.println("Initialization block");
            instanceVariable = Math.round(3.5f);
            staticVariable = Math.round(3.5f);
        }

        B() {
            System.out.println("Constructor");
        }

        public static void main(String[] args) {
            A a = new B();
            a.print();
            System.out.println("main");
        }

        void print() {
            System.out.println(instanceVariable);
        }

        static void somethingElse() {
            System.out.println("Static method");
        }
    }

Trước khi bắt đầu nhận xét về mã nguồn, tôi sẽ cung cấp cho bạn một lời giải thích ngắn về các biến tĩnh của một lớp:

Điều đầu tiên là chúng được gọi là biến lớp, chúng thuộc về lớp không thuộc trường hợp cụ thể của lớp. Tất cả các thể hiện của lớp chia sẻ biến tĩnh (lớp) này. Mỗi và mọi biến có một giá trị mặc định, tùy thuộc vào kiểu nguyên thủy hoặc kiểu tham chiếu. Một điều nữa là khi bạn gán lại biến tĩnh trong một số thành viên của lớp (khối khởi tạo, hàm tạo, phương thức, thuộc tính) và làm như vậy bạn sẽ thay đổi giá trị của biến tĩnh không phải là ví dụ cụ thể, bạn sẽ thay đổi nó cho tất cả trường hợp. Để kết luận phần tĩnh tôi sẽ nói rằng các biến tĩnh của một lớp được tạo không phải khi bạn khởi tạo lần đầu tiên của lớp, chúng được tạo khi bạn định nghĩa lớp của bạn, chúng tồn tại trong JVM mà không cần bất kỳ trường hợp nào.<CLASS_NAME>.<STATIC_VARIABLE_NAME>).

Bây giờ hãy xem mã ở trên:

Điểm vào là phương thức chính - chỉ có ba dòng mã. Tôi muốn tham khảo ví dụ hiện đang được phê duyệt. Theo nó, điều đầu tiên phải được in sau khi in "Khối khởi tạo tĩnh" là "Khối khởi tạo" và đây là sự bất đồng của tôi, khối khởi tạo không tĩnh không được gọi trước hàm tạo, nó được gọi trước bất kỳ khởi tạo nào của hàm tạo của lớp trong đó khối khởi tạo được xác định.

Có một sự tạo đa hình của một đối tượng, nhưng trước khi vào lớp B và phương thức chính của nó, JVM khởi tạo tất cả các biến lớp (tĩnh), sau đó đi qua các khối khởi tạo tĩnh nếu có tồn tại và sau đó vào lớp B và bắt đầu với thực hiện phương thức chính. Nó đi đến hàm tạo của lớp B sau đó ngay lập tức (ngầm) gọi hàm tạo của lớp A, sử dụng đa hình phương thức (phương thức ghi đè) được gọi trong phần thân của hàm tạo của lớp A là hàm được định nghĩa trong lớp B và trong trường hợp này biến có tên instanceVariable được sử dụng trước khi khởi tạo lại. Sau khi đóng hàm tạo của lớp B, luồng được trả về cho hàm tạo của lớp B nhưng trước tiên nó sẽ chuyển sang khối khởi tạo không tĩnh trước khi in "Trình xây dựng". Để hiểu rõ hơn về việc gỡ lỗi nó với một số IDE,

|
  • 1

    TL; DR OP chỉ đơn giản yêu cầu giải thích về khối khởi tạo, không phải là lời giải thích dài dòng về các nguyên tắc cơ bản của các biến tĩnh, hàm tạo hoặc tùy chọn IDE của bạn.

    – Trịnh Sơn Lâm 07:19:47 29/08/2014
  • 1

    Đôi khi, những lời giải thích dài dòng này có thể trở nên phổ biến bất ngờ. Hoặc là nếu những người hỏi câu hỏi ban đầu thực sự cần một lời giải thích dài dòng để có được nền tảng của họ thẳng. Hoặc nếu mọi người tự đọc câu trả lời, như thể đó là một blog về một chủ đề nhất định. Trong trường hợp này, tôi cũng không nói như vậy.

    – Hoàng Nguyên Bảo 20:08:54 14/04/2017
  • 1

    @nenito, tôi nghĩ rằng nhận xét của bạn về câu trả lời được chấp nhận là sai lệch. Tôi khuyến khích bạn viết lại nó thành một cái gì đó giống như "Tôi có một lời giải thích sắc thái hơn có thể được quan tâm." Câu trả lời được chấp nhận dường như là chính xác, đơn giản là không chi tiết như của bạn.

    – Phan Long Vịnh 01:32:01 20/04/2017
  • 1

    @Glen Pierce: Câu trả lời được chấp nhận đã được sửa đổi sau bình luận của tôi. Câu của tôi không chỉ đưa ra câu trả lời mà còn một số thông tin bổ sung mà tôi nghĩ là hữu ích cho các nhà phát triển Java cấp trung học và trung cấp.

    – Tạ Vũ Quân 07:12:19 21/04/2017
1

Khối khởi tạo chứa mã luôn được thực thi bất cứ khi nào một thể hiện được tạo. Nó được sử dụng để khai báo / khởi tạo phần chung của các hàm tạo khác nhau của một lớp.

Thứ tự của các hàm tạo khởi tạo và khối khởi tạo không thành vấn đề, khối khởi tạo luôn được thực thi trước hàm tạo.

Điều gì xảy ra nếu chúng ta muốn thực thi một số mã một lần cho tất cả các đối tượng của một lớp?

Chúng tôi sử dụng Khối tĩnh trong Java.

|
0
public class StaticInitializationBlock {

    static int staticVariable;
    int instanceVariable;

    // Static Initialization Block
    static { 
        System.out.println("Static block");
        staticVariable = 5;

    }

    // Instance Initialization Block
    { 

        instanceVariable = 7;
        System.out.println("Instance Block");
        System.out.println(staticVariable);
        System.out.println(instanceVariable);

        staticVariable = 10;
    }


    public StaticInitializationBlock() { 

        System.out.println("Constructor");
    }

    public static void main(String[] args) {
        new StaticInitializationBlock();
        new StaticInitializationBlock();
    }

}

Đầu ra:

Static block
Instance Block
5
7
Constructor
Instance Block
10
7
Constructor
|
0

Câu hỏi không hoàn toàn rõ ràng, nhưng đây là một mô tả ngắn gọn về cách bạn có thể khởi tạo dữ liệu trong một đối tượng. Giả sử bạn có một lớp A chứa danh sách các đối tượng.

1) Đặt giá trị ban đầu vào khai báo trường:

class A {
    private List<Object> data = new ArrayList<Object>();
}

2) Gán các giá trị ban đầu trong hàm tạo:

class A {
    private List<Object> data;
    public A() {
        data = new ArrayList<Object>();
    }
}

Cả hai đều cho rằng bạn không muốn truyền "dữ liệu" làm đối số của hàm tạo.

Mọi thứ trở nên khó khăn hơn một chút nếu bạn trộn các hàm tạo quá tải với dữ liệu nội bộ như trên. Xem xét:

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        data = new ArrayList<Object>();
        name = "Default name";
        userFriendlyName = "Default user friendly name";
    }

    public B(String name) {
        data = new ArrayList<Object>();
        this.name = name;
        userFriendlyName = name;
    }

    public B(String name, String userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

Lưu ý rằng có rất nhiều mã lặp đi lặp lại. Bạn có thể khắc phục điều này bằng cách làm cho các hàm tạo gọi nhau hoặc bạn có thể có một phương thức khởi tạo riêng mà mỗi hàm tạo gọi:

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        this("Default name", "Default user friendly name");
    }

    public B(String name) {
        this(name, name);
    }

    public B(String name, String userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

hoặc là

class B {
    private List<Object> data;
    private String name;
    private String userFriendlyName;

    public B() {
        init("Default name", "Default user friendly name");
    }

    public B(String name) {
        init(name, name);
    }

    public B(String name, String userFriendlyName) {
        init(name, userFriendlyName);
    }

    private void init(String _name, String _userFriendlyName) {
        data = new ArrayList<Object>();
        this.name = name;
        this.userFriendlyName = userFriendlyName;
    }
}

Hai là tương đương (nhiều hơn hoặc ít hơn).

Tôi hy vọng điều đó cung cấp cho bạn một số gợi ý về cách khởi tạo dữ liệu trong các đối tượng của bạn. Tôi sẽ không nói về các khối khởi tạo tĩnh vì có lẽ nó hơi tiến bộ vào lúc này.

EDIT: Tôi đã giải thích câu hỏi của bạn là "làm thế nào để tôi khởi tạo các biến đối tượng của mình", chứ không phải "làm thế nào để các khối khởi tạo hoạt động" vì các khối khởi tạo là một khái niệm tương đối nâng cao và từ giai điệu của câu hỏi có vẻ như bạn đang hỏi về khái niệm đơn giản hơn. Tôi có thể sai.

|
  • 1

    Ngay cả khi bạn diễn giải câu hỏi là "Làm thế nào để tôi khởi tạo các biến thể hiện của mình?", Câu trả lời của bạn không đề cập rằng nó có thể được thực hiện với các công cụ khởi tạo.

    – Dương Thành Tâm 11:33:16 02/12/2014
0

Các khối khởi tạo được thực thi bất cứ khi nào lớp được khởi tạo và trước khi các hàm tạo được gọi. Chúng thường được đặt phía trên các nhà xây dựng trong niềng răng. Hoàn toàn không cần thiết phải đưa chúng vào các lớp học của bạn.

Chúng thường được sử dụng để khởi tạo các biến tham chiếu. Đây trang đưa ra một lời giải thích tốt

|

Câu trả lời của bạn (> 20 ký tự)

Bằng cách click "Đăng trả lời", bạn đồng ý với Điều khoản dịch vụ, Chính sách bảo mật and Chính sách cookie của chúng tôi.

Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ hoặc hỏi câu hỏi của bạn.