简体   繁体   中英

Access to private field of a super class

As everyone knows, private fields are not inherited between classes. What intrigues me, is how it works for inner static classes. Consider the following code:

public class Main {
    public static void main(String[] args) {
        new B();
    }

    private static class A {
        private int a = 10;

        private void foo() {
            System.out.println("A.foo");
        }
    }

    private static class B extends A {
        {
            // foo();    // compile-time error
            super.foo();    // ok

            // System.out.println(a);    // compile-time error
            System.out.println(super.a);    // ok
        }
    }
}

Can you please explain how it is possible to access private fields of other inner class? And if it is legal, why it is possible only via "super.XXX" construct?

Inner classes were a late entry to Java. When they were added they were added as a compiler extension only, no change to the JVM.

The language spec stated that an inner class was allowed to access the private members of the class that it was declared within; that includes other inner classes.

To make it work, the compiler generates bridge methods. Using javap with Main$A from the example above looks like this:

Notice the addition of access$200 and access$300. They provide back door access to the private method and field respectively.

class Main$A {
  Main$A(Main$1);
    Code:
       0: aload_0       
       1: invokespecial #3                  // Method "<init>":()V
       4: return        

  static void access$200(Main$A);
    Code:
       0: aload_0       
       1: invokespecial #2                  // Method foo:()V
       4: return        

  static int access$300(Main$A);
    Code:
       0: aload_0       
       1: getfield      #1                  // Field a:I
       4: ireturn       
}

For completeness, here is the generated code for Main$B. Notice the calls to access$200 and 300, they appear where super.a and super.foo() appeared in the Java code.

class Main$B extends Main$A {
  public Main$B();
    Code:
       0: aload_0       
       1: aconst_null   
       2: invokespecial #1                  // Method Main$A."<init>":(LMain$1;)V
       5: aload_0       
       6: invokestatic  #2                  // Method Main$A.access$100:(LMain$A;)V
       9: getstatic     #3                  // Field java/lang/System.out:Ljava/io/PrintStream;
      12: aload_0       
      13: invokestatic  #4                  // Method Main$A.access$200:(LMain$A;)I
      16: invokevirtual #5                  // Method java/io/PrintStream.println:(I)V
      19: return        
}

And if it is legal, why it is possible only via "super.XXX" construct?

private fields are not usually part of the compilers resolution path for fields, by forcing developers to specify super the compiler is making certain that private access is what was meant and not a mistake.

From JLS3 6.6.1 : "A private class member or constructor is accessible only within the body of the top level class (§7.6) that encloses the declaration of the member or constructor. It is not inherited by subclasses..

Since inner class is accessible within the body of top class hence its accessible and child classes are out of the enclosing class. Now the specification doesn't say how this should happen - that's not really the job of a specification. It's really up to the implementation programmers to make it happen, and those details are not documented in the current specs.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM