2010-10-05 39 views
10

Tôi đã chạy vào khối mã này ngày hôm nay và tôi không biết nó hoạt động như thế nào. Tôi biết cách tạo các lớp ẩn danh, nhưng tôi thường thấy chữ ký phương thức và không chỉ là một cặp dấu ngoặc. Mã giữa các dấu ngoặc đó có được đặt thành một khối tĩnh không? Liệu nó đi vào constructor? Hay nó là cái gì khác hoàn toàn?Cú pháp Java Đường

conext.checking(new Expectations() { 
    { // <- what does this pair of braces do? 
     oneOf(alarm).getAttackAlarm(null); 
    } 
}); 

Trả lời

15

Đây là trình khởi tạo phiên bản gọi mã bên trong với ngữ cảnh của đối tượng đã tạo.

này tương đương với

Expectations exp = new Expectations(); 
exp.oneOf(alarm).getAttackAlarm(null); 
conext.checking(exp) 

Ai đã viết nó có thể đã nghĩ rằng ông đã là hiệu quả hơn bằng cách không khai báo một biến (không đúng) hoặc đó là mã sạch hơn (Tôi không đồng ý).

Nơi chính rằng những initializers có ích như thế này là khi bản đồ instantiating, ví dụ:

Map map = new HashMap() {{ 
    put("key1", "value1"); 
    put("key2", "value2"); 
}}; 

mà tôi nghĩ thực sự là hơi dễ đọc hơn.

+1

Nó được gọi là một "ví dụ initializer", không phải là một "tĩnh initializer" (các sau này sẽ không có 'điều này' vì lý do rõ ràng). Ngoài ra, hãy xem http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.6 –

+1

Nó không phải là bộ khởi tạo tĩnh, chỉ là một trình khởi tạo (ví dụ). Khối đó sẽ được chạy * mọi lúc * mã đó được chạy, không chỉ lần đầu tiên như sẽ xảy ra với bộ khởi tạo tĩnh. –

+0

Lưu ý hay, tôi đã chỉnh sửa điều đó .... –

0

Đây là khối khởi tạo. Tôi không thể nói nó làm gì mà không nhìn vào phần còn lại của mã.

Bí quyết là tưởng tượng "kỳ vọng mới()" được thay thế bằng "class Something extends Expectation".

0

Điều gì đang xảy ra? Các dấu ngoặc ôm bên ngoài tạo một lớp ẩn danh mới bắt nguồn từ Ngoại lệ. Các dấu ngoặc đơn bên trong bên trong xác định trình khởi tạo và đặt oneOf() v.v.

Tại sao phải làm như vậy? Đó là một mẹo nhỏ để xây dựng và khởi tạo một thể hiện của một lớp. e. đôi khi bạn thấy một cái gì đó như thế này:

new Set<String>(){{add("one");add("two")}} 

để khởi tạo nội dung của bộ sưu tập.

Nhược điểm? Vì bạn đang tạo một lớp ẩn danh trong lớp có chứa, lớp ẩn danh đó chứa một tham chiếu này tới lớp bên ngoài một cách ngầm định. Thông thường không phải là một vấn đề, nhưng nó có thể gây ra vấn đề nếu (nói) bạn muốn serialise một lớp học mà bạn đã xây dựng như thế này.

+0

Không phải là bộ khởi tạo * tĩnh *. – DJClayworth

+0

Ah. Lỗi của tôi. Sửa lỗi –

3

Đây là khối khởi tạo, nhưng không nhất thiết là một khối khởi tạo tĩnh. Nó có hiệu quả là một hàm tạo cho một lớp bên trong vô danh. Thông thường, bạn sẽ thấy mẫu "khởi tạo đúp đúp" này để tạo và điền các bộ sưu tập một cách thuận tiện:

private final Collection<Integer> FIXED_COLLECTION = Collections.unmodifiableCollection(new HashSet<Integer>() 
{ // first set of braces declares anonymous inner class 
    { add(1); add(2); add(3); } // second set is initializer block 
}); 
+0

Tôi phải nói, trong 15 năm lập trình Java, tôi chưa bao giờ bắt gặp một người khởi tạo được sử dụng như thế trước đây. – dty

3

Đây là trình khởi tạo thể hiện (không phải là trình khởi tạo tĩnh).

xem xét định nghĩa của một lớp

public class Foo { 
    private int i = getDefaultValue(); 

    private static int getDefaultValue() { 
     return 5; 
    } 
} 

Các cuộc gọi đến getDefaultValue() rằng initalises i bản chất là một khối mã chạy mỗi lần một thể hiện của Foo được xây dựng. Ký pháp mở rộng hàm đó để cho phép khởi tạo phức tạp hơn. Ví dụ.

public class Foo { 
    private int i; 

    { 
     int z = 4 + 5; 
     i = z + getDefaultValue(); 
    } 

    private static int getDefaultValue() { 
     return 5; 
    } 
} 

Cách thức mà nó được sử dụng trong JMock là một mẹo để đưa ra kỳ vọng về cấu trúc đóng.

+0

+1 để lưu ý việc sử dụng bên ngoài các lớp ẩn danh. Tôi cũng thích tham chiếu đến đóng cửa! :-) – dty

0

Các lớp bên trong đồng nhất không có hàm tạo, vì vậy bạn có thể định nghĩa một trình khởi tạo thể hiện như thế này, tức là bộ niềng răng bên trong là các trình khởi tạo thể hiện.

new Expectations() { 
    { 
     oneOf(alarm).getAttackAlarm(null); 
    } 
} 
+1

Cú pháp này không giới hạn ở các lớp ẩn danh. Mặc dù việc sử dụng nó không cần thiết và gây nhầm lẫn trong một lớp học thông thường. – dty

0

Động lực chính đằng sau này, tôi tin rằng, là tạo ra một không gian tên mới, trong đó tên quy định tại Expection thể được tham chiếu một cách dễ dàng hơn.

Ví dụ, giả java.lang.Math không phải là cuối cùng,

new Math() 
{{ 
    double x = sin(23.65); 
    double y = log(x); 
    ... 
}}; 

Nó gần như là nếu chúng ta có một cái gì đó giống như

with names from Math 
{ 
    double x = sin(23.65); 
    double y = log(x); 
    ... 
} 
Các vấn đề liên quan