2011-12-09 33 views
16

Tôi đã tạo một enum với một biến thành viên riêng. Khi tôi cố gắng truy cập vào biến thành viên, các trình biên dịch nói 'Không thể tạo tham chiếu tĩnh đến thành phần trường không tĩnh'.Không thể tạo tham chiếu tĩnh cho thành viên trường không tĩnhVariable với biến riêng

Nếu biến không phải là riêng tư (ví dụ: được bảo vệ hoặc gói được bảo vệ) thì nó biên dịch tốt. Tôi không hiểu phạm vi của biến phải làm gì với loại (tĩnh, không tĩnh) của hàm trừu tượng được triển khai.

Ai đó có thể khai sáng cho tôi không?

public enum EnumWithAbstractMethodAndMembers { 
    TheOneAndOnly(1) { 
     @Override 
     public int addValue(final int value) { 
      return memberVariable + value; 
     } 
    }; 

    private final int memberVariable; 

    private EnumWithAbstractMethodAndMembers(final int memberVariable) { 
     this.memberVariable = memberVariable; 
    } 

    abstract int addValue(int value); 

} 

Trả lời

19

Thông báo lỗi gây nhầm lẫn.

Vấn đề là khi bạn cung cấp mã giá trị enum, bạn đang tạo một lớp phụ ẩn danh của enum. (Lớp của nó sẽ là EnumWithAbstractMethodAndMembers$1) Một lớp con không thể truy cập các thành viên riêng của siêu lớp của nó, tuy nhiên các lớp lồng nhau có thể thông qua phương thức accessor được tạo ra. Bạn sẽ có thể truy cập vào trường riêng tư và thông báo lỗi mà nó cung cấp cho bạn có vẻ như đang dẫn đến lỗi.

BTW Bạn có thể sử dụng điều này, nhưng bạn không cần phải IMHO.

public int addValue(final int value) { 
     return super.memberVariable + value; 
    } 

Dưới đây là một ví dụ ngắn tôi sẽ đăng nhập như một lỗi trong các thông báo lỗi vì nó không dẫn đến một giải pháp cho vấn đề.

public enum MyEnum { 
    One { 
     public int getMemberVariableFailes() { 
      // error: non-static variable memberVariable cannot be referenced from a static context 
      return memberVariable; 
     } 

     public int getMemberVariable2OK() { 
      return memberVariable2; 
     } 

     public int getMemberVariableOK() { 
      return super.memberVariable; 
     } 
    }; 

    private final int memberVariable = 1; 
    final int memberVariable2 = 1; 
} 

Dựa trên phản hồi của Tom Hawkin của, ví dụ này nhận được thông báo lỗi tương tự.

public class MyNotEnum { 
    // this is the static context in which the anonymous is created 
    public static final MyNotEnum One = new MyNotEnum() { 
     public int getMemberVariableFailes() { 
      // error: non-static variable memberVariable cannot be referenced from a static context 
      return memberVariable; 
     } 

     public int getMemberVariableOK() { 
      return super.memberVariable; 
     } 
    }; 
    private final int memberVariable = 1; 
} 

để so sánh

public class MyNotEnum { 
    public class NestedNotEnum extends MyNotEnum { 
     public int getMemberVariableFailes() { 
      // compiles just fine. 
      return memberVariable; 
     } 

     public int getMemberVariableOK() { 
      return super.memberVariable; 
     } 
    } 
    private final int memberVariable = 1; 
} 
+0

hợp lý của âm thanh. Thx cho câu trả lời và gợi ý với 'siêu'. – Andreas

+0

Tôi đã đăng nhập nó dưới dạng lỗi 'javac'. –

+1

Họ nói rằng nó sẽ được hiển thị trong một vài ngày. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7119746 Tôi đã nhận thấy Oracle chấp nhận lỗi của tôi ** nhanh hơn ** nhiều so với Sun. –

0

Nguyên nhân chính của lỗi là: bạn đang cố gắng để làm tài liệu tham khảo để biến tư nhân (memberVariable) của siêu lớp từ lớp thực hiện nội tâm.

Để thực hiện mã lỗi miễn phí bạn có thể làm một trong hai sau đây:

  • bạn phải sử dụng super.memberVariable từ memberVariablekhông địa phương-TheOnlyAndOnly()
  • bạn có thể làm int memberVariablecông.
  • bạn có thể làm:

    TheOneAndOnly(1) { 
        int memberVariable=4; 
        @Override 
        public int addValue(final int value) { 
         return memberVariable + value; 
        } 
    }; 
    
3

Một vấn đề tương tự được bao phủ trong Java Puzzlers bởi Josh Bloch và Neal Gafter (Tôi không biết nơi một trong hai bản sao của tôi là, vì vậy tôi không thể cung cấp cho bạn một tham chiếu chính xác).

Không có gì đặc biệt về enums. Bất kỳ lớp bên trong vô danh (hoặc cục bộ) nào trong một ngữ cảnh tĩnh sẽ làm. Các quy tắc là lớp bên ngoài được xem xét trước lớp siêu. Điều này làm cho rất nhiều ý nghĩa cho các lớp như vậy trong một bối cảnh không tĩnh.Nếu thay đổi ngữ cảnh thành tĩnh thay đổi biến nào đã được tra cứu, thì đó là khả năng giới thiệu "nhầm lẫn" trong thời gian chạy (C++ là tích cực hơn nhiều với loại quy tắc này).

Lớp bên trong mở rộng lớp bên ngoài có quyền truy cập vào các trường cá thể riêng của lớp bên ngoài, cho dù thông qua this hoặc một số trường hợp khác.

Khi chúng tôi được phép truy cập, chúng tôi cần bằng cách nào đó chỉ định chúng tôi muốn đi qua bên trong này chứ không phải bên ngoài này. Như Peter Lawrey chỉ ra super.member sẽ làm. Bạn cũng có thể chọn khu vực nội này, và sau đó sử dụng biểu:

 return ((EnumWithAbstractMethodAndMembers)this).memberVariable + value; 

Hoặc

 EnumWithAbstractMethodAndMembers innerThis = this; 
     return innerThis.memberVariable + value; 
Các vấn đề liên quan