2009-09-03 31 views
41

Giá trị trung bình của khối trong mã sau là {{ ... }}?Ý nghĩa của lớp mới (...) {{...}} thành ngữ khởi tạo

class X { 

    private Y var1; 

    private X() { 
     Z context = new Z(new SystemThreadPool()) {{ 
      var1 = new Y(); 
     }}; 
    } 

} 
+5

Tôi đoán không dễ dàng với google đối với dấu ngoặc kép. –

+3

@Tom Hawtin: Bạn có thể Google cho "cú đúp đúp" thay vì ... –

Trả lời

62

Được gọi là double curly brace initialization. (EDIT: Liên kết đã bị xóa, archived here)

Điều đó có nghĩa là bạn đang tạo một phân lớp ẩn danh và mã trong dấu ngoặc kép về cơ bản là một hàm tạo. Nó thường được sử dụng để thêm nội dung vào các bộ sưu tập bởi vì cú pháp của Java để tạo ra những gì về cơ bản là các hằng số thu thập có phần khó xử.

Vì vậy, bạn có thể làm:

List<String> list = new ArrayList<String>() {{ 
    add("one"); 
    add("two"); 
    add("three"); 
}}; 

thay vì:

List<String> list = new ArrayList<String>(); 
list.add("one"); 
list.add("two"); 
list.add("three"); 

Tôi thực sự không thích điều đó và thích làm điều này:

List<String> list = Arrays.asList("one", "two", "three"); 

Vì vậy, nó doesn' t có ý nghĩa nhiều trong trường hợp đó trong khi nó làm cho, nói, Maps, mà không có một người trợ giúp thuận tiện.

+0

@skaffman Nó rất hữu ích trong "java lỏng" như [JATL] (http://code.google.com/p/jatl) cố gắng. –

+6

Lưu ý rằng Arrays.asList() trả về java.util.Arrays.ArrayList.ArrayList và không phải java.util.ArrayList, có chức năng giới hạn. – Asaf

+3

Kỹ thuật này là khó khăn và có một số cảnh báo. Có thể kết thúc bằng hợp đồng bị hỏng() hoặc sử dụng bộ nhớ tăng lên mà không có lý do chính đáng nào. Tốt hơn bạn nên tránh việc khởi tạo đúp đúp, trừ khi bạn biết chính xác mình đang làm gì. Xem bài viết [this] (http://www.ayp-sd.blogspot.com/2012/12/double-brace-initialization-in-java.html) để biết thêm chi tiết. –

11

Dấu ngoặc nhọn "bên ngoài" có nghĩa là bạn đang tạo một lớp con ẩn danh, dấu ngoặc thứ hai là bộ khởi tạo đối tượng. Trình khởi tạo được chạy trước hàm tạo của lớp, nhưng sau bất kỳ lệnh gọi super nào (và do đó cũng sau bất kỳ trình khởi tạo siêu lớp nào). Bạn cũng có thể sử dụng initializers trong các lớp không ẩn danh, đây là cách thuận tiện để khởi tạo các trường final nếu bạn có nhiều hàm tạo không thể gọi cho nhau hoặc các trường cần khởi tạo phức tạp hơn khởi tạo trường thông thường.

xem xét lớp này:

class X extends Y{ 
    private final int lulz; 

    private static boolean someCondition(){...} 
    private static boolean danger() throws SomeException { ... } 
    public X(A a) throws SomeException { 
     super(a); 
     lulz = someCondition()? danger() : 0; 
    } 
    public X(B b) throws SomeException { 
     super(b); 
     lulz = someCondition()? danger() : 0; 
    } 
} 

Nó có thể được viết lại như sau:

class X extends Y{ 
    private final int lulz; 

    private static boolean someCondition(){...} 
    private static boolean danger() throws SomeException { ... } 
    { // initalizer -- might throw SomeException! 
     lulz = someCondition()? danger() : 0; 
    } 
    public X(A a) throws SomeException { super(a); } 
    public X(B b) throws SomeException { super(b); } 
} 

Nếu initializer có thể ném một ngoại lệ kiểm tra, tất cả các nhà xây dựng phải tuyên bố rằng họ có thể ném nó.

4

Bạn đang tạo một anonymous class và sử dụng thành ngữ class Instance initialize r, như thế này:

class X { 
    private Y var1; 

    private X() { 
     Z context = new Z(
       new SystemThreadPool()) { 
        {      // This is the initialize idiom 
         var1 = new Y();  // 
        }      // 
       } 
     ); // BTW you are missing ")" 
    } 
} 
1

Như đã đề cập trong câu trả lời trước, đúp cú đúp xoăn khởi là đúng.

Sử dụng kỹ thuật cụ thể để Khởi tạo các thành viên sơ thẩm bằng Java. Nó là một cách viết tắt để định nghĩa trong một định nghĩa lớp, một khối mã được chia sẻ sẽ chạy khi bất kỳ hàm tạo lớp nào được kích hoạt.

Tôi đang thêm liên kết vào số official Java documentations mô tả nó để có cái nhìn rộng hơn về chủ đề.

Từ documentation:

khối Initializer cho các biến dụ trông giống như tĩnh khối khởi tạo, nhưng không có từ khóa tĩnh:

{

// whatever code is needed for initialization goes here 

}

Trình biên dịch Java sao chép các khối khởi tạo int o mọi nhà xây dựng. Do đó, phương pháp này có thể được sử dụng để chia sẻ một khối mã giữa nhiều nhà xây dựng.

Các vấn đề liên quan