和上面一样,使用javap反编译看一下。不过这次我们先看一下InnerClass的结果
16:03$javap-cAnotherOuterClass$InnerClass
Compiledfrom"AnotherOuterClass.java"
classAnotherOuterClass$InnerClassextendsjava.lang.Object{
finalAnotherOuterClassthis$0;
AnotherOuterClass$InnerClass(AnotherOuterClass);
Code:
0:aload_0
1:aload_1
2:putfield#12;//Fieldthis$0:LAnotherOuterClass;
5:aload_0
6:invokespecial#14;//Methodjava/lang/Object."<init>":()V
9:aload_0
10:bipush10
12:putfield#17;//Fieldx:I
15:return
staticintaccess$0(AnotherOuterClass$InnerClass);
Code:
0:aload_0
1:getfield#17;//Fieldx:I
4:ireturn
}
  又出现了,编译器又自动生成了一个获取私有属性的后门方法access$0一次来获取x的值。
  AnotherOuterClass.class的反编译结果
16:08 $ javap -c AnotherOuterClass
Compiled from "AnotherOuterClass.java"
public class AnotherOuterClass extends java.lang.Object{
public AnotherOuterClass();
Code:
0:  aload_0
1:  invokespecial    #8; //Method java/lang/Object."<init>":()V
4:  return
public static void main(java.lang.String[]);
Code:
0:  new  #16; //class AnotherOuterClass$InnerClass
3:  dup
4:  new  #1; //class AnotherOuterClass
7:  dup
8:  invokespecial    #18; //Method "<init>":()V
11: dup
12: invokevirtual    #19; //Method java/lang/Object.getClass:()Ljava/lang/Class;
15: pop
16: invokespecial    #23; //Method AnotherOuterClass$InnerClass."<init>":(LAnotherOuterClass;)V
19: astore_1
20: getstatic    #26; //Field java/lang/System.out:Ljava/io/PrintStream;
23: new  #32; //class java/lang/StringBuilder
26: dup
27: ldc  #34; //String InnerClass Filed =
29: invokespecial    #36; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
32: aload_1
33: invokestatic #39; //Method AnotherOuterClass$InnerClass.access$0:(LAnotherOuterClass$InnerClass;)I
36: invokevirtual    #43; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
39: invokevirtual    #47; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
42: invokevirtual    #51; //Method java/io/PrintStream.println:(Ljava/lang/String;)V
45: return
}
  其中这句调用是外部类通过内部类的实例获取私有属性x的操作
  33:   invokestatic #39; //Method AnotherOuterClass$InnerClass.access$0:(LAnotherOuterClass$InnerClass;)I
  再来个总结
  其中java官方文档 有这样一句话
  if the member or constructor is declared private, then 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.
  意思是 如果(内部类的)成员和构造方法设定成了私有修饰符,当且仅当其外部类访问时是允许的。
  如何让内部类私有成员不被外部访问
  相信看完上面两部分,你会觉得,内部类的私有成员想不被外部类访问都很困难吧,谁让编译器“爱管闲事”呢,其实也是可以做到的。那是使用匿名内部类。
  由于mRunnable对象的类型为Runnable,而不是匿名内部类的类型(我们无法正常拿到),而Runanble中没有x这个属性,所以mRunnable.x是不被允许的。
public class PrivateToOuter {
Runnable mRunnable = new Runnable(){
private int x=10;
@Override
public void run() {
System.out.println(x);
}
};
public static void main(String[] args){
PrivateToOuter p = new PrivateToOuter();
//System.out.println("anonymous class private filed= "+ p.mRunnable.x); //not allowed
p.mRunnable.run(); // allowed
}
}
  后总结
  在本文中,private表面上看上去失效了,但实际上是没有的,而是在调用时通过间接的方法来获取私有的属性。
  Java的内部类构造时持有对外部类的应用,C++不会,这一点和C++不一样。