2015-01-02 14 views
13

Tôi có một sự hiểu lầm về một lớp ẩn danh trong Java là gì. Hãy xem xét các ví dụ đơn giản sau:Tại sao một lớp ẩn danh trong một ngữ cảnh tĩnh hợp lệ

public static void main (String[] args) throws java.lang.Exception 
{ 
    B b = new B(){ }; 
    System.out.println(b.b); 
} 

interface B{ int b = 1; } 

DEMO

Tại sao mã biên dịch? Số JLS, chapt 15 cho biết:

Lớp ẩn danh luôn là lớp bên trong (§8.1.3); nó không bao giờ là tĩnh

Nhưng JLS, chapt 8

Một lớp bên trong là một lớp lồng nhau đó không phải là rõ ràng hoặc ngầm tuyên bố tĩnh.

Vì vậy, lớp ẩn danh là một lớp bên trong. Nhưng chúng ta sử dụng chúng trong bối cảnh tĩnh. Tại sao nó chính xác ở đây?

+0

'B b = new B() {};' không phải là một lớp ẩn danh.Và nó hoạt động bởi vì nó được * sử dụng trong * một ngữ cảnh tĩnh, nó tuyên bố lớp bên trong chính nó tĩnh bị cấm. –

+0

@Shywim Vì vậy, loại đối tượng được tạo ra bởi 'new B() {} 'là gì? –

Trả lời

7

Một lớp học có thể được tạo ra trong một bối cảnh tĩnh mà không bị tuyên bố tĩnh, và đây là những gì đang xảy ra đây. Chúng ta hãy nhìn vào những gì được công bố tĩnh, và được tạo ra trong một bối cảnh tĩnh có nghĩa là:

Sự khác biệt giữa một lớp vô danh tạo ra trong một bối cảnh tĩnh và một bối cảnh không tĩnh là liệu nó có một ví dụ kèm theo:

Nếu C là một lớp vô danh, sau đó:

  • Nếu biểu thức tạo lớp dụ xảy ra trong một bối cảnh tĩnh, sau đó tôi đã không ngay lập tức kèm theo ví dụ.

  • Nếu không, trường hợp kèm theo ngay lập tức của i là này.

Một lớp lồng nhau được khai báo tĩnh phép các thành viên tĩnh:

Một lớp bên trong là một lớp lồng nhau đó là không rõ ràng hoặc ngầm tuyên bố tĩnh.

Lớp lồng nhau không phải là lớp bên trong có thể khai báo thành viên tĩnh một cách tự do, phù hợp với các quy tắc thông thường của ngôn ngữ lập trình Java .

Bằng cách nói một lớp lồng nhau đó là 'implicity tuyên bố tĩnh', nó đề cập đến những thứ như các lớp học trong giao diện:

Một lớp học thành viên của giao diện là mặc nhiên tĩnh (§9.5) như vậy là không bao giờ được coi là một lớp bên trong.

Lớp ẩn danh không được khai báo tĩnh (không rõ ràng với từ khóa, hoặc ngầm như ở bên trong giao diện) và do đó không cho phép khai báo thành viên tĩnh. Tuy nhiên, chúng có thể được tạo ra trong một bối cảnh tĩnh, có nghĩa là chúng không đề cập đến một cá thể kèm theo.

Bởi vì các lớp ẩn danh không được khai báo tĩnh, cả hai dấu ngoặc kép trong câu hỏi đều nhất quán.

3

Bạn nên phân biệt giữa các lớp ẩn danh và nội

Với tuyên bố này, bạn tạo ra một lớp thực hiện các giao diện B. Lớp không có tên nên nó được gọi là một lớp vô danh. Các javac biên dịch sẽ tạo ra một tập tin lớp với sau đặt tên quy tắc YourClass $ 1.class (trong đó 1 là một số tuần tự, dựa trên số lượng của các tầng lớp vô danh trong YourClass.

B b = new B(){ }; 

Lớp tạo ra bởi new B(){ } có thể không được khai báo là tĩnh ("một lớp vô danh luôn luôn là một lớp bên trong (§8.1.3), nó không bao giờ tĩnh")..

một tĩnh lồng lớp dụ

class YourClass { 
    static class StaticNestedClass { 
    } 
} 

một ví dụ không tĩnh lồng lớp

class YourClass { 
    // An inner class is a nested class that is not explicitly or implicitly declared static. 
    class InnerClass { 
    } 
} 

Có hai loại lớp lồng nhau: tĩnh và không tĩnh. Các lớp lồng nhau được khai báo tĩnh là cái gọi là static nested classes, trong khi các lớp lồng nhau không được khai báo là tĩnh được gọi là inner classes.

+1

Chúng tôi đang tìm kiếm câu trả lời trích dẫn JLS thay vì từ sự hiểu biết của bạn. – nhahtdh

+2

Đây là giới thiệu cơ bản về các lớp bên trong nhưng không giải quyết được câu hỏi nào cả. – chrylis

1

B là giao diện bên trong . Như vậy B là ngầm tĩnh và bạn có thể tham chiếu B trong một ngữ cảnh tĩnh. (Từ JLS 8.5.1: Giao diện thành viên ẩn hoàn toàn (§9.1.1).)

Nhưng lớp vô danh tạo ra thông qua B không phải là tĩnh, và nếu tham chiếu từ một bối cảnh không tĩnh, bạn có thể nhận được quyền truy cập vào các đối tượng bên ngoài:

public class Main{ 

    public static void main(String[] args) throws java.lang.Exception { 
     B b = new B() { 

      @Override 
      public Ess3 getParent() { 
       //return Ess3.this; ERROR : non static variable cannot be referenced from static context 
       return null; 
      } 
     }; 
     System.out.println(b.b); 
    } 

    interface B { 

     int b = 1; 
     Ess3 getParent(); 
    } 

    /* a non static method */ 
    void foo() { 
     B b = new B() { 

      @Override 
      public Ess3 getParent() { 
       return Ess3.this; // this anonymous class is not static 
      } 

     }; 

    } 
} 

Trong ví dụ của bạn, bạn có thể nghĩ rằng bạn tạo ra một lớp bên trong vô danh tĩnh, bởi vì bạn tạo ra nó:

  • từ một giao diện lồng tĩnh
  • trong một bối cảnh tĩnh - vì vậy không có quyền truy cập vào các đối tượng bên ngoài

Nhưng cùng tuyên bố trong một bối cảnh không tĩnh chứng minh rằng một giao diện lồng tĩnh tạo ra một tổ chức phi lớp nặc danh tĩnh

+0

Vui lòng trích dẫn từ JLS để tăng cường khiếu nại của bạn. – nhahtdh

+0

@nhahtdh: Tôi nghĩ OP đã trích dẫn phần liên quan của JLS nhưng tôi đã đọc nó trong một câu trả lời khác. Đã chỉnh sửa bài đăng –

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