我一直在努力理解java中嵌套类的机制.
考虑以下代码:
public class OuterClass {
private String privateOuterField = "Private Outer Field";
public static String publicStaticOuterField = "Public static outer field";
private static String privateStaticOuterField = "private static outer field";
class InnerClass{
private String privateInnerField = "Private Inner Field";
//non-final static data members not allowed in java 1.8 but allowed in java 17.0
//private static String innerClassStaticField = "Private Inner Class Static Field";
public void accessMembers() {
System.out.println(privateOuterField);
System.out.println(publicStaticOuterField);
}
}
static class StaticInnerClass{
private String privateStaticInnerField = "Private Inner Field of static class";
public void accessMembers(OuterClass outer) {
//System.out.println(privateOuterField); //error
System.out.println(outer.privateOuterField);
System.out.println(publicStaticOuterField);
System.out.println(privateStaticOuterField);
}
}
public static void main(String[] args) {
OuterClass outerObj = new OuterClass();
OuterClass.InnerClass innerObj = outerObj.new InnerClass();
StaticInnerClass staticInnerObj = new StaticInnerClass();
innerObj.accessMembers();
staticInnerObj.accessMembers(outerObj);
}
}
我知道内部类是编译器的一种现象,虚拟机并没有意识到它们.内部类被转换为常规类文件,外部类名和内部类名之间用$分隔.
为了更详细地理解这种机制,我try 使用javap-p命令反汇编java 1.8版编译的类文件.
我得到了以下结果:
public class staticNestedClasses.OuterClass {
private java.lang.String privateOuterField;
public static java.lang.String publicStaticOuterField;
private static java.lang.String privateStaticOuterField;
public staticNestedClasses.OuterClass();
public static void main(java.lang.String[]);
static java.lang.String access$000(staticNestedClasses.OuterClass);
static java.lang.String access$100();
static {};
}
内部类别:
class staticNestedClasses.OuterClass$InnerClass {
private java.lang.String privateInnerField;
final staticNestedClasses.OuterClass this$0;
staticNestedClasses.OuterClass$InnerClass(staticNestedClasses.OuterClass);
public void accessMembers();
}
在这里我们可以看到,编译器通过构造函数将外部类的引用传递给内部类,以便判断外部类的字段和方法:
staticNestedClasses.OuterClass$InnerClass(staticNestedClasses.OuterClass);
这个外部类引用存储在final staticNestedClasses.OuterClass this$0
中
但是OuterClass$InnerClass类不能通过外部类引用直接访问私有成员,所以每当编译器检测到从内部类访问私有成员时,它都会在外部类中生成访问器方法(或getter方法).
在外部类的反汇编文件中,我们可以看到编译器生成了这些访问器方法.
static java.lang.String access$000(staticNestedClasses.OuterClass);
static java.lang.String access$100();
但当我在java 17.0中编译相同的代码并反汇编类文件时,我得到了以下结果.
外层舱:
public class staticNestedClasses.OuterClass {
private java.lang.String privateOuterField;
public static java.lang.String publicStaticOuterField;
private static java.lang.String privateStaticOuterField;
public staticNestedClasses.OuterClass();
public static void main(java.lang.String[]);
static {};
}
OuterClass$内部类别:
class staticNestedClasses.OuterClass$InnerClass {
private java.lang.String privateInnerField;
private static java.lang.String innerClassStaticField;
final staticNestedClasses.OuterClass this$0;
staticNestedClasses.OuterClass$InnerClass(staticNestedClasses.OuterClass);
public void accessMembers();
static {};
}
这里是compiler did not generate any accessor methods,但代码运行良好.
So how did the inner class access private members of outer class?