Java 嵌套 类 的可见性如何工作?

How does visibility work for Java nested classes?

我正在尝试了解分配给嵌套 classes 的可见性,除了我的 IDE 对我大喊大叫我必须做的事情。这可能会变得任意复杂,所以我需要了解一般规则。

public class A {
    private static class B {
        public int foo; // accessible in A?
        private int bar; // accessible in A?
        public static class C { // accessible in A? everywhere?
        }
        private static class D { // accessible in A?
        }
    }
}

据我了解,修饰符似乎在 "file" 级别解析,而不是封装 class 级别。一旦一件事是私有的,它里面的任何东西都是私有的。

这个或技术解释的实际机制是什么?这是否记录在某处,或者我只需要阅读 JLS?

我见过的关于访问可见性的最佳总结之一是 Java Tutorials > Controlling access to members of a class, but it glosses over some of the key details. The question I think you are asking is answered in § 6.6.1 of the JLS for SE 7: "Determining Accessibility"

If ... public ... Otherwise, if ... protected ... Otherwise, if ... package access ...

Otherwise, the member or constructor is declared private, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

如果你仔细阅读:

  1. 任意访问
  2. 顶层正文内class
  3. 给另一个 private 成员(不是包私有的 - 那是不同的)成员
  4. 无论嵌套多深
  5. 允许

因此:私有嵌套 classes 的任何深度内的任何成员都可以访问 顶层 class 的主体 内的任何地方(包括其他嵌套兄弟classes)。但是,私有嵌套 class 以及其中的任何成员对其他顶级 classes 不可见。

例如:

public class A {
    private static class B {
        public int foo; // accessible in A and P
        private int bar; // accessible in A and P   
        public static void test(){
            P p = new P();
            p.foo = 1; p.bar = 1;
        }
    }
    private static class P {
        public int foo; // accessible in A and B
        private int bar; // accessible in A and B   
        public static void test(){
            B b = new B();
            b.foo = 1; b.bar = 1;
        }
    }
    public static void test(){
        B b = new B();
        b.foo = 1; b.bar = 1;
        P p = new P();
        p.foo = 1; p.bar = 1;       
    }
}

注意: 不过这不是 "file level"。在该文件中声明另一个顶级 class(不能是 public - 每个文件只允许其中一个)并且它看不到那些相同的嵌套 private 成员。

class X {
    public static void test() {
        // all of these statements fail ...
        A.B b = new A.B();
        b.foo = 1; b.bar = 1; 
        b.test();
        A.P p = new A.P();
        p.foo = 1; p.bar = 1;  
        p.test();
    }

}

无障碍是相对于访问源而言的。第一

Otherwise, the member or constructor is declared private, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.

因此,您在 A 中声明或嵌套在 A 中的 class 中的所有成员都可以在 A 中访问。

如果您不在 A 中,则无法访问 Aprivate 位成员。这意味着 B 不可访问。由于 foobarCDB 的成员,您需要 B 才能访问它们。但是由于无法访问 B,因此您也无法访问它们。

public class Unrelated {
   {
       B b; // nope
       A.B b; // nope
       A.B.C c; // nope 
   }
}

这些规则或多或少都在JLS的this section中定义。