Java: Khi nào thì khối khởi tạo tĩnh hữu ích?


91

Sự khác biệt giữa khởi tạo trong một statickhối là gì:

public class staticTest {

    static String s;
    static int n;
    static double d;

    static {
        s = "I'm static";
        n = 500;
        d = 4000.0001;
    }
    ...

Và khởi tạo tĩnh riêng lẻ:

public class staticTest {

    static String s = "I'm static";
    static int n    = 500;
    static double d = 4000.0001;

    ....

1
Bạn chỉ sử dụng các phép gán trong khối khởi tạo tĩnh, vì vậy tất nhiên chúng có thể được thực hiện bằng cách sử dụng phép gán biến tĩnh. Bạn đã thử xem điều gì sẽ xảy ra nếu bạn cần thực hiện các câu lệnh không gán chưa?
Platinum Azure vào

Đây là một nơi tốt để tải các lớp hoặc tải thư viện gốc.
qrtt1 21/02/12

1
Lưu ý rằng nên tránh các biến tĩnh và do đó các khối khởi tạo tĩnh nói chung không phải là một ý tưởng tuyệt vời. Nếu bạn thấy mình sử dụng chúng nhiều, bạn có thể sẽ gặp một số rắc rối.
Bill K

Câu trả lời:


107

Các khối khởi tạo tĩnh cho phép khởi tạo phức tạp hơn, ví dụ như sử dụng các điều kiện:

static double a;
static {
    if (SomeCondition) {
      a = 0;
    } else {
      a = 1;
    }
}

Hoặc khi yêu cầu nhiều hơn chỉ xây dựng: khi sử dụng trình tạo để tạo phiên bản của bạn, việc xử lý ngoại lệ hoặc công việc khác ngoài việc tạo trường tĩnh là cần thiết.

Một khối khởi tạo tĩnh cũng chạy sau các bộ khởi tạo tĩnh nội tuyến, vì vậy điều sau là hợp lệ:

static double a;
static double b = 1;

static {
    a = b * 4; // Evaluates to 4
}

3
Đang thực hiện "b = a * 4;" nội tuyến sẽ chỉ là một vấn đề nếu b được khai báo trước a, điều này không đúng trong ví dụ của bạn.
George Hawkins

1
@GeorgeHawkins Tôi chỉ đang cố gắng minh họa rằng một trình khởi tạo tĩnh chạy sau các trình khởi tạo nội tuyến, không phải là một trình khởi tạo tương đương không thể được thực hiện trong nội tuyến. Tuy nhiên, tôi hiểu ý bạn và đã cập nhật ví dụ để (hy vọng) rõ ràng hơn.
Rich O'Kelly

1
Nói cho vui, tôi có thể chỉ ra rằng ví dụ đầu tiên của bạn có thể dễ dàng như "static double a = someCondition? 0: 1;" Không phải là ví dụ của bạn không phải là lớn, tôi chỉ sayin ... :)
Bill K

18

Một cách sử dụng điển hình:

private final static Set<String> SET = new HashSet<String>();

static {
    SET.add("value1");
    SET.add("value2");
    SET.add("value3");
}

Bạn sẽ làm như thế nào nếu không có bộ khởi tạo tĩnh?


2
Trả lời: Ổi :) +1
Paul Bellora

2
Một câu trả lời khác không có thư viện bổ sung: tạo một phương thức tĩnh đóng gói quá trình khởi tạo SETvà sử dụng biến khởi tạo ( private final static Set<String> SET = createValueSet()). Điều gì sẽ xảy ra nếu bạn có 5 bộ và 2 bản đồ, bạn sẽ đổ tất cả chúng vào một statickhối duy nhất ?
TWiStErRob

14

Bạn có thể sử dụng khối try / catch bên trong static{}như bên dưới:

MyCode{

    static Scanner input = new Scanner(System.in);
    static boolean flag = true;
    static int B = input.nextInt();
    static int H = input.nextInt();

    static{
        try{
            if(B <= 0 || H <= 0){
                flag = false;
                throw new Exception("Breadth and height must be positive");
            }
        }catch(Exception e){
            System.out.println(e);
        }

    }
}

PS: Tham khảo từ này !


11

Xử lý ngoại lệ trong quá trình khởi tạo là một lý do khác. Ví dụ:

static URL url;
static {
    try {
        url = new URL("https://blahblah.com");
    }
    catch (MalformedURLException mue) {
        //log exception or handle otherwise
    }
}

Điều này hữu ích cho các hàm tạo gây phiền nhiễu cho các ngoại lệ đã được kiểm tra, như ở trên hoặc logic khởi tạo phức tạp hơn có thể dễ xảy ra ngoại lệ.


5

Đôi khi bạn muốn làm nhiều việc hơn là chỉ gán giá trị cho các biến tĩnh. Vì bạn không thể đặt các câu lệnh tùy ý trong thân lớp, bạn có thể sử dụng khối khởi tạo tĩnh.


4

Trong ví dụ của bạn, không có sự khác biệt; nhưng thường thì giá trị ban đầu phức tạp hơn được thể hiện một cách thoải mái trong một biểu thức (ví dụ: đó là giá trị List<String>có nội dung được thể hiện tốt nhất bằng for-loop; hoặc giá trị đó Methodcó thể không tồn tại, vì vậy cần có các trình xử lý ngoại lệ) và / hoặc các trường tĩnh cần được đặt theo một thứ tự cụ thể.


4

statickhối có thể được sử dụng để khởi tạo cá thể singleton , để ngăn chặn việc sử dụng phương pháp đồng bộ hóa getInstance() .


3

Về mặt kỹ thuật, bạn có thể đi mà không có nó. Một số thích mã khởi tạo nhiều dòng để chuyển sang một phương thức tĩnh. Tôi khá hài lòng khi sử dụng trình khởi tạo tĩnh để khởi tạo đa câu lệnh tương đối đơn giản.

Tất nhiên, tôi hầu như luôn tạo tĩnh của mình finalvà trỏ đến một đối tượng không thể thay đổi.


3

Từ khóa static (cho dù đó là một biến hay một khối) đều thuộc về lớp. Vì vậy, khi lớp được gọi, các biến hoặc khối này được thực thi. Vì vậy, hầu hết việc khởi tạo sẽ được thực hiện với sự trợ giúp của từ khóa tĩnh. Vì nó thuộc về chính lớp, nên lớp có thể truy cập trực tiếp vào nó mà không cần tạo một thể hiện của lớp.

Hãy lấy một ví dụ, Có một lớp giày trong đó có một số biến như màu sắc, kích cỡ, thương hiệu, v.v. Và ở đây nếu công ty sản xuất giày chỉ có một thương hiệu thì chúng ta nên khởi tạo nó dưới dạng biến tĩnh. Vì vậy, khi lớp giày được gọi và các loại giày khác nhau được sản xuất (bằng cách tạo một thể hiện của lớp) lúc đó màu sắc và kích cỡ sẽ chiếm bộ nhớ bất cứ khi nào giày mới được tạo ra nhưng ở đây thương hiệu là tài sản chung cho tất cả các loại giày, để nó sẽ chiếm bộ nhớ một lần cho dù có bao nhiêu đôi giày được sản xuất.

Thí dụ:

    class Shoe {
    int size;
    String colour;
    static String brand = "Nike";

    public Shoe(int size, String colour) {
        super();
        this.size = size;
        this.colour = colour;
    }

    void displayShoe() {
        System.out.printf("%-2d %-8s %s %n",size,colour, brand);
    }

    public static void main(String args[]) {
        Shoe s1 = new Shoe(7, "Blue");
        Shoe s2 = new Shoe(8, "White");

        System.out.println("=================");
        s1.displayShoe();
        s2.displayShoe();
        System.out.println("=================");
    }
}

1

Chúng tôi sử dụng các hàm tạo để khởi tạo các biến thể hiện của chúng tôi (các biến không tĩnh, các biến thuộc về các đối tượng, không phải lớp).

Nếu bạn muốn khởi tạo các biến lớp (biến tĩnh) và muốn thực hiện điều đó mà không cần tạo một đối tượng (các hàm tạo chỉ có thể được gọi khi tạo một đối tượng), thì bạn cần các khối tĩnh.

static Scanner input = new Scanner(System.in);
static int widht;
static int height;

static
{
    widht = input.nextInt();
    input.nextLine();
    height = input.nextInt();
    input.close();

    if ((widht < 0) || (height < 0))
    {
        System.out.println("java.lang.Exception: Width and height must be positive");
    }
    else
    {
        System.out.println("widht * height = " + widht * height);
    }
}

Đọc stdin trong trình khởi tạo tĩnh là một ý tưởng khá tệ. Và System.out.println("B * H");là khá vô dụng. Và câu trả lời chính nó là khá mơ hồ. OP không đề cập đến các hàm tạo hoặc biến cá thể.
shmosel

Đây chỉ là một ví dụ cho thấy trình khởi tạo tĩnh là gì và nó được sử dụng như thế nào. OP không yêu cầu hàm tạo hoặc biến cá thể nhưng để dạy anh ta sự khác biệt của bộ khởi tạo tĩnh với hàm tạo, anh ta cần biết điều đó. Nếu không, anh ấy sẽ nói "Tại sao tôi không sử dụng một hàm tạo để khởi tạo các biến tĩnh của mình?"
Michael

0

Khối mã tĩnh cho phép khởi tạo các trường với nhiều hơn là cài đặt, khởi tạo các trường theo thứ tự khác nhau của các khai báo và cũng có thể được sử dụng để nhập có điều kiện.

Cụ thể hơn,

static final String ab = a+b;
static final String a = "Hello,";
static final String b = ", world";

sẽ không hoạt động vì a và b được khai báo sau ab.

Tuy nhiên, tôi có thể sử dụng một init tĩnh. để khắc phục điều này.

static final String ab;
static final String a;
static final String b;

static {
  b = ", world";
  a = "Hello";
  ab = a + b;
}

static final String ab;
static final String a;
static final String b;

static {
  b = (...) ? ", world" : ", universe";
  a = "Hello";
  ab = a + b;
}

3
Mặc dù những gì bạn đang nói là đúng, nhưng nó không chứng minh sự cần thiết của khối khởi tạo tĩnh. Bạn chỉ có thể di chuyển phần abkhai báo của mình bên dưới phần khai báo của b.
gawi

0

Một khối khởi tạo tĩnh rất hữu ích nếu một, bạn muốn intialize các kiểu tĩnh của lớp đã chỉ định, trước khi sử dụng lớp đầu tiên. Việc sử dụng tiếp theo sẽ không gọi bất kỳ khối khởi tạo tĩnh nào. Nó đối lập trực tiếp với trình khởi tạo cá thể, khởi tạo các thành viên cá thể.


0

Khi bạn muốn đánh giá bất kỳ biểu thức nào đó trong thời gian tải lớp thì bạn có thể sử dụng khối tĩnh nhưng hãy nhớ:

Bạn phải xử lý một ngoại lệ trong khối tĩnh nghĩa là bạn không thể ném một ngoại lệ khỏi khối tĩnh.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.