2015-04-15 17 views
14

Tôi muốn tạo một enum trong đó mỗi hằng số có Map được liên kết với nó. Tôi thực hiện điều này bằng cách cho mỗi liên tục khởi tạo một thể hiện, như vậy:Tại sao tính toán này được biên dịch?

import java.util.HashMap; 
import java.util.Map; 

public enum Derp { 
    FOO {{ 
      mMap.put("bar", 1); 
     }}; 

    // cannot be private 
    protected final Map<String, Integer> mMap = new HashMap<>(); 
} 

Tôi thấy rằng nếu mMapprivate, nó không thể được tham chiếu trong initializer dụ. Lỗi là Cannot make a static reference to the non-static field mMap. Trước khi lý do cho điều này xảy ra với tôi, tôi tham khảo ý kiến ​​JLS §8.9.2, mà nói trong phần:

Đó là một lỗi thời gian biên dịch cho các nhà thầu, khối dụ initializer, hoặc dụ biểu thức khởi tạo biến của một enum liên tục e để tham khảo e hoặc đến một hằng số enum cùng loại được khai báo ở bên phải e.

Không phải tôi phá vỡ quy tắc này bằng cách mặc nhiên tham khảo FOO trong intializer dụ riêng FOO 's? Làm thế nào để biên dịch? Nó không chỉ biên dịch, mà còn hoạt động chính xác khi chạy.

(Nó xảy ra với tôi rằng mMap không thể private vì tôi ngầm tạo ra một lớp con nặc danh mà không thể tham chiếu đến một lĩnh vực private trong lớp cha của nó. Đó là một chút kỳ lạ trong bản thân kể từ enums đang ngầm final ...)

+1

"enums đang ngầm 'final'" - [không hoàn toàn] (http://ideone.com/3bi0U1). Java cần tạo các lớp con ngầm mỗi trường hợp mỗi lần bạn làm điều với các dấu ngoặc bên cạnh hằng số enum, vì vậy nếu bạn làm điều đó, lớp enum không phải là cuối cùng. Tuy nhiên, bạn vẫn không thể khai báo các lớp con của riêng mình. – user2357112

+1

Đủ điều kiện cuộc gọi như 'super.mMap.put (...);'. Lý do đằng sau điều này chỉ là một đặc điểm kỹ thuật kỳ lạ. – Radiodef

+0

@Radiodef Tôi không tin rằng đây là bản sao. Tôi nghĩ rằng tấm áp phích này hỏi hai câu hỏi mà không được hỏi trong bài đăng liên kết: (1) tại sao nó hợp pháp nếu anh ta sử dụng 'protected' và (2) tại sao không phải là tham chiếu tự ngầm tiềm ẩn. Tôi nhìn qua các câu trả lời ở đó, và họ không trả lời câu hỏi cho sự hài lòng của tôi. – ajb

Trả lời

4

đó là một lỗi thời gian biên dịch cho các nhà thầu, khối dụ initializer, hoặc dụ biểu thức khởi tạo biến của một enum liên tục e để chỉ e hoặc một hằng số enum cùng loại được khai báo ở bên phải của e.

Các đặc điểm kỹ thuật ở đây chỉ có nghĩa là bạn không thể tham khảo bởi tên vì lĩnh vực này được gọi bằng e không được khởi tạo được nêu ra. Điều đó không có nghĩa là bạn không thể truy cập this.

Về cơ bản, quy tắc này giống với bất kỳ trình khởi tạo nào khác (như int x = x;).

Chúng ta có thể thấy tại sao với một ví dụ tương tự (Ideone):

enum Example { 
    INSTANCE {{ 
     subversion(); 
    }}; 

    static void subversion() { 
     System.out.println(INSTANCE); 
    } 

    public static void main(String[] args) { 
     System.out.println(INSTANCE); 
    } 
} 

Những kết quả đầu ra

null 
INSTANCE 

Tôi thấy rằng nếu mMap là tư nhân, nó có thể không được nhắc đến trong khởi tạo cá thể.

Bạn có thể đủ điều kiện cuộc gọi là super.mMap.put(...);. Riêng tư mMap không được kế thừa, nhưng có thể truy cập từ lớp bên trong. I also covered this here. Ngắn gọn của nó là tên đơn giản mMap đề cập đến một trường hợp bên ngoài không tồn tại của Derp.

Chúng ta có thể xác minh điều này là trường hợp với một ví dụ tương tự (Ideone):

class Example { 
    private int x; 

    class Inner extends Example {{ 
     x = 1;  // refers to the outer instance 
     super.x = 2; // refers to the inner instance 
    }} 

    public static void main(String[] args) { 
     Example outer = new Example(); 
     Example inner = outer.new Inner(); 
     System.out.println(outer.x); // prints 1 
     System.out.println(inner.x); // prints 2 
    } 
} 

Ngoại trừ trong trường hợp của bạn FOO là tĩnh như vậy không có ví dụ ngoài — do đó trình biên dịch lỗi.

1

Đó là vì FOO là lớp con ẩn danh của riêng nó là Derp - đã tồn tại khi FOO được tạo.

public class Enums { 
    public enum Derp { 
     FOO {{ 
      mMap.put("bar", 1); 
     }}; 

     // cannot be private 
     protected final Map<String, Integer> mMap = new HashMap<>(); 
    } 

    public static void main(String[] args) { 
     System.out.println(Derp.class); 
     System.out.println(Derp.FOO.getClass()); 
    } 
} 

lớp Enums $ derp
lớp Enums $ derp $ 1

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