2009-07-08 20 views
14

Thật không may tôi đã không mã hóa Java trong khoảng năm năm và tôi hoàn toàn không thể nhớ làm thế nào hoặc tại sao mã sau đây đang làm việc.Gọi hàm tạo này với các dấu ngoặc kép sau đây là gì?

Tôi tình cờ gặp một ví dụ tương tự và chia nhỏ nó thành điều này. Sự nhấn mạnh là ở phần bên dưới bình luận: Tôi không nhận được ký hiệu hàm tạo theo sau là khối trong dấu ngoặc kép. Và tiếc là tôi không thể tìm thấy bất cứ điều gì trong tài liệu Java hoặc bằng cách sử dụng Google (những từ nào tôi nên google?).

package syntaxtest; 

public class Main { 

    public static void main(String[] args) { 

     // What kind of notation is this? 
     MyTest tester = new MyTest() {{ 
      setName("John Johnson"); 
     }}; 

     System.out.println(tester.getName()); 
    } 
} 


class MyTest { 
    private String name; 

    public String getName() { 
     return name; 
    } 

    public void setName(String name) { 
     this.name = name; 
    } 
} 

Vì vậy, đây là những câu hỏi của tôi:

  1. như thế nào ký hiệu này/cú pháp gọi là?
  2. Tôi có thể đọc một số tài liệu về nó ở đâu?

Tôi đoán/hy vọng tôi sẽ tự mình trả lời câu hỏi thứ hai nếu ai đó có thể cung cấp cho tôi câu trả lời cho câu hỏi đầu tiên.

Để làm rõ: Tôi biết đầu ra là John Johnson;) Nhưng tôi không biết tại sao nó hoạt động.

+0

Khi tôi lần đầu tiên nhìn thấy nó trên Usenet tôi phải nhìn vào nó trong một thời gian trước khi nhận ra những gì đang xảy ra. Một khi bạn biết nó là gì, nó hiển nhiên. –

+0

Tôi thấy mẹo này gọn gàng một thời gian trước đây trên SO, nhưng tôi cũng thấy khá một vài tuyên bố từ chối nói rằng nó rất dễ dàng để phá vỡ các công cụ với nó/không phải là rất đáng tin cậy. Nếu tôi định thử sử dụng nó, tôi chắc chắn sẽ cân nhắc rằng A) Tôi phải giải thích nó cho mọi người xem mã từ đó, và B) Tôi phải làm một số nghiên cứu để hiểu tất cả các tác động của việc sử dụng mẫu này. –

+0

Cảm ơn tất cả các bạn đã trả lời nhanh chóng và hữu ích! – klekker

Trả lời

20

này được gọi là double brace initialization:

Các cú đúp đầu tiên tạo ra một mới AnonymousInnerClass, thứ hai tuyên bố một thể hiện initializer khối được chạy khi các bên trong lớp vô danh được khởi tạo. Đây là loại khối initializer được chính thức gọi là một "dụ initializer", bởi vì nó được khai báo trong phạm vi dụ của lớp - "initializers tĩnh" là một khái niệm có liên quan nơi tĩnh từ khóa được đặt trước cú đúp bắt đầu khối, và đó được thực hiện ở cấp lớp trong thời gian sớm như classloader hoàn thành tải lớp (quy định tại http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6) khối initializer có thể sử dụng bất kỳ phương pháp, các lĩnh vực và các biến thức sẵn trong chứa phạm vi, nhưng phải có cảnh giác với thực tế là trình khởi chạy được chạy trước nhà thầu.

Tùy chọn này chỉ hoạt động cho các lớp học phi không chính thức vì nó tạo ra một lớp con ẩn danh .

14

Hãy bố trí mã một chút khác nhau:

MyTest tester = new MyTest() { 
    { 
    setName("John Johnson"); 
    } 
}; 

Những gì bạn thấy ở đây được gọi là cú đúp đúp khởi. Bạn có một lớp con bên trong vô danh của lớp MyTest, cùng với khối khởi tạo, là một khối có chứa mã được chạy khi đối tượng được xây dựng.

Thông thường, bạn sẽ đặt mã như vậy trong hàm tạo, nhưng vì các lớp bên trong vô danh không thể có các hàm tạo nên đây là cách duy nhất để đảm bảo mã được chạy khi được yêu cầu.

Có nói rằng, có một chút xấu xí khi thực hiện việc này. Có những cách tốt hơn. Tuy nhiên, tôi sử dụng nó bản thân mình trong dịp, thường là trong các thành ngữ sau đây để tạo ra một bản đồ bất biến:

final Map<String, Integer> textToInt = Collections.unmodifiableMap(new HashMap<String, Integer>() {{ 
    put("one", 1); 
    put("two", 2); 
    // etc 
}}); 

nào tạo ra một bản đồ mới, ghi đè nó, bổ sung một số giá trị nó trong khối khởi tạo và kết thúc tốt đẹp nó trong một bản đồ không thể sửa đổi.

-5
MyTest tester = new MyTest() {{ 
    setName("John Johnson"); 
}}; 

cũng giống như

MyTest tester = new MyTest(); 
tester.setName("John Johnson"); 
+3

Chúng không giống nhau. Kết quả của họ không phải là cùng một lớp. Một tạo ra một thể hiện của MyTest. Cái kia tạo một thể hiện của một lớp con ẩn danh của MyTest. Nếu phương thức equals của bạn trông như thế này: boolean công bằng bằng (Đối tượng khác) { nếu (other.class! = MyTest.class) {return false; } // một số kiểm tra khác ... } thì sẽ không xem xét chúng giống nhau. –

+3

@mangst Tôi nghĩ bạn nên nói rằng họ là "Chức năng tương đương với hầu hết các mục đích"; bạn phải là một người nhỏ bé ở đây - bản chất của các kỹ sư và tất cả ... –

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