public class Subclass extends Superclass { int subMember; private void interestingMethod(){ System.out.println("Subclass is interesting"); } @Override protected void notSoInteresting() { super.notSoInteresting(); System.out.println("Subclass is not so interesting."); } public void accessInnerClassFields(){ Innerclass innerClass = new Innerclass(); innerClass.innerClassId = 3; } public class Innerclass{ private long innerClassId = 32L; void changeOuterMember(){ subMember = 3; } } public void accessInnerStaticClassFields(){ EricLiu eric = new EricLiu(); long copyEricId = eric.ericId; } public static class EricLiu{ private long ericId = 123L; } }
Let's look at the methods accessInnerStaticClassFields() and accessInnerClassFields(). They both access the private fields of an inner class, either a static one or non-static one. How does that happen?
The Java Virtual Machine has no idea that they are inner classes so it should prevent another class from accessing the EricLiu and InnerClass's private class members.
Let's dive into the bytecode. call javap -v -p -s -sysinfo -constants Subclass.class
to dissect the outer class first.
public void accessInnerClassFields();
Signature: ()V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=1
0: new #37 // class Subclass$Innerclass
3: dup
4: aload_0
5: invokespecial #39 // Method Subclass$Innerclass."<init>":(LSubclass;)V
8: astore_1
9: aload_1
10: ldc2_w #42 // long 3l
13: invokestatic #44 // Method Subclass$Innerclass.access$0:(LSubclass$Innerclass;J)V
16: return
LineNumberTable:
line 23: 0
line 24: 9
line 25: 16
LocalVariableTable:
Start Length Slot Name Signature
0 17 0 this LSubclass;
9 8 1 innerClass LSubclass$Innerclass;
public void accessInnerStaticClassFields();
Signature: ()V
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: new #51 // class Subclass$EricLiu
3: dup
4: invokespecial #53 // Method Subclass$EricLiu."<init>":()V
7: astore_1
8: aload_1
9: invokestatic #54 // Method Subclass$EricLiu.access$0:(LSubclass$EricLiu;)J
12: lstore_2
13: return
LineNumberTable:
line 36: 0
line 37: 8
line 38: 13
LocalVariableTable:
Start Length Slot Name Signature
0 14 0 this LSubclass;
8 6 1 eric LSubclass$EricLiu;
13 1 2 copyEricId J
Apparently the accessInnerClassFields() method has called an method named:
Subclass$Innerclass.access$0
to access the inner class instance's private field.
and the accessInnerStaticClassFields() method calls the method named:
Subclass$EricLiu.access$0
to access the inner static class instance's private field. So what are these access$0 methods?
Now let's take a look at the bytecode of the inner classes.
We found that the compiler has automatically created a static method inside of both inner classes for the outer class to access the fields. No matter the inner class is a static class or non-static.
Notice at bytecode level, static methods can access non-static fields
static void access$0(Subclass$Innerclass, long);
Signature: (LSubclass$Innerclass;J)V
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=3, locals=3, args_size=2
0: aload_0
1: lload_1
2: putfield #19 // Field innerClassId:J
5: return
LineNumberTable:
line 28: 0
LocalVariableTable:
Start Length Slot Name Signature
static long access$0(Subclass$EricLiu);
Signature: (LSubclass$EricLiu;)J
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: getfield #14 // Field ericId:J
4: lreturn
LineNumberTable:
line 35: 0
LocalVariableTable:
Start Length Slot Name Signature
That is the reason why outer class can access inner class instances' private fields.
No comments:
Post a Comment