2013-08-22 38 views
5
public enum MyEnum1 { 

    FOO(BAR), BAR(FOO); 

    private MyEnum1 other; 

    private MyEnum1(MyEnum1 other) { 
     this.other = other; 
    } 

    public MyEnum1 getOther() { 
     return other; 
    } 

} 

MyEnum1 tạo ra lỗi Cannot reference a field before it is defined, đó là khá dễ hiểu, vì trật tự tuyên bố vấn đề ở đây. Nhưng tại sao biên dịch sau đây?Dường như tôi * có thể tham khảo một lĩnh vực trước khi nó được định nghĩa *

public enum MyEnum2 { 

    FOO { public MyEnum2 getOther() { return BAR; } }, 
    BAR { public MyEnum2 getOther() { return FOO; } }; 

    public abstract MyEnum2 getOther(); 

} 

FOO đề cập đến BAR trước BAR được định nghĩa, tôi sai?

+0

Không phải hằng số 'enum' được biên dịch thành các cấu trúc tương tự như các lớp? Trả về 'BAR', bạn đang thực sự đề cập đến một kiểu. Đọc [ở đây] (http://stackoverflow.com/questions/7276775/what-does-java-compile-an-enumeration-down-to): _set giá trị hợp lệ được tạo tại thời điểm khởi tạo kiểu_ –

+0

[JLS] (http : //docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9.1) nói _Sơ thể lớp tùy chọn của một hằng số enum ngầm định nghĩa một khai báo lớp ẩn danh (§15.9. 5) mở rộng kiểu enum kèm theo ngay lập tức._ –

Trả lời

2

Các bộ phận JLS quan trọng là thisthis

Một lớp học hoặc giao diện kiểu T sẽ được khởi tạo ngay trước khi sự xuất hiện đầu tiên của bất kỳ một trong các cách sau:

T là một lớp và một Ví dụ của T được tạo ra.

T là một lớp và phương thức tĩnh được khai báo bởi T được gọi.

Trường tĩnh được khai báo bằng T được gán.

Trường tĩnh được khai báo bằng T được sử dụng và trường không phải là hằng số biến (§4.12.4).

T là một cấp cao nhất (§7.6), và một tuyên bố khẳng định (§14.10) lexically lồng nhau trong T (§8.1.3) được thực thi.

Cơ thể lớp tùy chọn của một hằng số enum ngầm định nghĩa một tuyên bố mang tính chất lớp (§15.9.5) kéo dài kiểu enum ngay kèm theo.

Vì vậy, với

FOO { public MyEnum2 getOther() { return BAR; } }, 
BAR { public MyEnum2 getOther() { return FOO; } }; 

bạn đang tạo hai lớp ẩn danh mở rộng MyEnum2.

Khi BAR cuối cùng là tham chiếu hoặc khi bạn gọi Foo.getOther() hoặc một số đoạn mã khác không MyEnum2.Bar, loại sẽ được khởi tạo.

1

bạn đang tạo hằng số enum với tham chiếu đến hằng số chưa khai báo trong trường hợp đầu tiên. Trong trường hợp thứ hai nó không quan trọng vì thứ tự biên dịch, hằng số liệt kê được biên dịch trước khi liệt kê thân. Tôi sẽ nói đây là lý do. Nếu nó không đúng, quá trình biên dịch sẽ thất bại trước đó vì khai báo phương thức trừu tượng được định nghĩa sau khai báo phương thức không trừu tượng trong phần thân của mỗi hằng số enum.

Tốt tham khảo - http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.9

1

Khi viết FOO(BAR), bạn đang thực sự gọi constructor của MyEnum1 và do đó BAR phải là đánh giá, đó là bất khả thi vào thời điểm đó kể từ BAR vẫn chưa được xác định.

Khi viết FOO {...}, bạn tạo một hằng số enum mới gọi là FOO, nhưng định một lớp ẩn danh mới. Vì định nghĩa lớp chỉ là được tải ('được tải' như trong 'Trình nạp lớp') vào thời điểm này và không có gì là chưa được đánh giá, không xảy ra lỗi. Sau đó, BAR {...} đang được tạo, phần còn lại của chương trình của bạn tiếp tục, v.v. và return BAR; (hoặc return FOO;) chỉ là được đánh giá khi bạn thực hiện cuộc gọi phương thức đến getOther(), điều này hoàn toàn có thể tại thời điểm đó vì cả hai hằng số đều vui vẻ sống tại thời điểm đó.

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