Java code.
The EnclosingClass has 2 local classes (classes that are defined within a code block). The ShoppingBag class is nested in a non-static method so it has access to all the non-static fields of the enclosing class; the Broom class is defined in a static method so it only has access to all the static fields of the enclosing class.
Compiler compiles this java file into 3 class files:
EnclosingClass.class
EnclosingClass$1ShoppingBag.class
EnclosingClass$1Broom.class
JVM has no idea that which is the enclosing class and which are the inner classes. So how does it give accesses to the enclosing class' fields to the 2 local classes?
Answer: the compiler creates public static methods inside the EnclosingClass for you automatically:
static int access$0(EnclosingClass);
static java.lang.String access$1(EnclosingClass);
static int access$2();
The Enclosingclass instance is passed in to the local class inside non-static method as a parameter of the constructor and is stored as a field in the EnclosingClass$1ShoppingBag.class
The Enclosingclass instance is passed in to the local class inside non-static method as a parameter of the constructor and is stored as a field in the EnclosingClass$1ShoppingBag.class
final EnclosingClass this$0;
flags: ACC_FINAL, ACC_SYNTHETIC
So the local class inside non-static method accesses the enclosing class' fields by calling access$n methods and passing in the EnclosingClass instance as a parameter.
However, local class inside static method doesn't store the enclosing class instance as a field and notice that the access$2() method doesn't require an enclosing class instance as the parameter, because local class in a static method can only access the static fields of the enclosing class.
Notice that on bytecode level: static methods can access non-static fields.
Now let's look at the bytecode.
---------------------EnclosingClass$1ShoppingBag.class---------------
class EnclosingClass$1ShoppingBag
SourceFile: "EnclosingClass.java"
EnclosingMethod: #20.#40 // EnclosingClass.doShopping
InnerClasses:
#43= #1; //ShoppingBag=class EnclosingClass$1ShoppingBag
minor version: 0
major version: 51
flags: ACC_SUPER
Constant pool:
#1 = Class #2 // EnclosingClass$1ShoppingBag
#2 = Utf8 EnclosingClass$1ShoppingBag
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 numOfBags
#6 = Utf8 I
#7 = Utf8 msg
#8 = Utf8 Ljava/lang/String;
#9 = Utf8 this$0
#10 = Utf8 LEnclosingClass;
#11 = Utf8 <init>
#12 = Utf8 (LEnclosingClass;)V
#13 = Utf8 Code
#14 = Fieldref #1.#15 // EnclosingClass$1ShoppingBag.this$0:LEnclosingClass;
#15 = NameAndType #9:#10 // this$0:LEnclosingClass;
#16 = Methodref #3.#17 // java/lang/Object."<init>":()V
#17 = NameAndType #11:#18 // "<init>":()V
#18 = Utf8 ()V
#19 = Methodref #20.#22 // EnclosingClass.access$0:(LEnclosingClass;)I
#20 = Class #21 // EnclosingClass
#21 = Utf8 EnclosingClass
#22 = NameAndType #23:#24 // access$0:(LEnclosingClass;)I
#23 = Utf8 access$0
#24 = Utf8 (LEnclosingClass;)I
#25 = Fieldref #1.#26 // EnclosingClass$1ShoppingBag.numOfBags:I
#26 = NameAndType #5:#6 // numOfBags:I
#27 = Methodref #20.#28 // EnclosingClass.access$1:(LEnclosingClass;)Ljava/lang/String;
#28 = NameAndType #29:#30 // access$1:(LEnclosingClass;)Ljava/lang/String;
#29 = Utf8 access$1
#30 = Utf8 (LEnclosingClass;)Ljava/lang/String;
#31 = Fieldref #1.#32 // EnclosingClass$1ShoppingBag.msg:Ljava/lang/String;
#32 = NameAndType #7:#8 // msg:Ljava/lang/String;
#33 = Utf8 LineNumberTable
#34 = Utf8 LocalVariableTable
#35 = Utf8 this
#36 = Utf8 LEnclosingClass$1ShoppingBag;
#37 = Utf8 SourceFile
#38 = Utf8 EnclosingClass.java
#39 = Utf8 EnclosingMethod
#40 = NameAndType #41:#18 // doShopping:()V
#41 = Utf8 doShopping
#42 = Utf8 InnerClasses
#43 = Utf8 ShoppingBag
{
int numOfBags;
flags:
java.lang.String msg;
flags:
final EnclosingClass this$0;
flags: ACC_FINAL, ACC_SYNTHETIC
EnclosingClass$1ShoppingBag(EnclosingClass);
flags:
Code:
stack=3, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #14 // Field this$0:LEnclosingClass;
5: aload_0
6: invokespecial #16 // Method java/lang/Object."<init>":()V
9: aload_0
10: iconst_3
11: aload_1
12: invokestatic #19 // Method EnclosingClass.access$0:(LEnclosingClass;)I
15: iadd
16: putfield #25 // Field numOfBags:I
19: aload_0
20: aload_1
21: invokestatic #27 // Method EnclosingClass.access$1:(LEnclosingClass;)Ljava/lang/String;
24: putfield #31 // Field msg:Ljava/lang/String;
27: return
LineNumberTable:
line 11: 0
line 12: 9
line 13: 19
LocalVariableTable:
Start Length Slot Name Signature
0 28 0 this LEnclosingClass$1ShoppingBag;
}
----------------------EnclosingClass$1Broom------------------------
class EnclosingClass$1Broom
SourceFile: "EnclosingClass.java"
EnclosingMethod: #20.#42 // EnclosingClass.cleanHouse
InnerClasses:
#45= #1; //Broom=class EnclosingClass$1Broom
minor version: 0
major version: 51
flags: ACC_SUPER
Constant pool:
#1 = Class #2 // EnclosingClass$1Broom
#2 = Utf8 EnclosingClass$1Broom
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 msg
#6 = Utf8 Ljava/lang/String;
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Methodref #3.#11 // java/lang/Object."<init>":()V
#11 = NameAndType #7:#8 // "<init>":()V
#12 = Class #13 // java/lang/StringBuilder
#13 = Utf8 java/lang/StringBuilder
#14 = String #15 // Take the broom and start cleaning.
#15 = Utf8 Take the broom and start cleaning.
#16 = Methodref #12.#17 // java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
#17 = NameAndType #7:#18 // "<init>":(Ljava/lang/String;)V
#18 = Utf8 (Ljava/lang/String;)V
#19 = Methodref #20.#22 // EnclosingClass.access$2:()I
#20 = Class #21 // EnclosingClass
#21 = Utf8 EnclosingClass
#22 = NameAndType #23:#24 // access$2:()I
#23 = Utf8 access$2
#24 = Utf8 ()I
#25 = Methodref #12.#26 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#26 = NameAndType #27:#28 // append:(I)Ljava/lang/StringBuilder;
#27 = Utf8 append
#28 = Utf8 (I)Ljava/lang/StringBuilder;
#29 = Methodref #12.#30 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#30 = NameAndType #31:#32 // toString:()Ljava/lang/String;
#31 = Utf8 toString
#32 = Utf8 ()Ljava/lang/String;
#33 = Fieldref #1.#34 // EnclosingClass$1Broom.msg:Ljava/lang/String;
#34 = NameAndType #5:#6 // msg:Ljava/lang/String;
#35 = Utf8 LineNumberTable
#36 = Utf8 LocalVariableTable
#37 = Utf8 this
#38 = Utf8 LEnclosingClass$1Broom;
#39 = Utf8 SourceFile
#40 = Utf8 EnclosingClass.java
#41 = Utf8 EnclosingMethod
#42 = NameAndType #43:#8 // cleanHouse:()V
#43 = Utf8 cleanHouse
#44 = Utf8 InnerClasses
#45 = Utf8 Broom
{
java.lang.String msg;
flags:
EnclosingClass$1Broom();
flags:
Code:
stack=4, locals=1, args_size=1
0: aload_0
1: invokespecial #10 // Method java/lang/Object."<init>":()V
4: aload_0
5: new #12 // class java/lang/StringBuilder
8: dup
9: ldc #14 // String Take the broom and start cleaning.
11: invokespecial #16 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
14: invokestatic #19 // Method EnclosingClass.access$2:()I
17: invokevirtual #25 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
20: invokevirtual #29 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
23: putfield #33 // Field msg:Ljava/lang/String;
26: return
LineNumberTable:
line 22: 0
line 23: 4
line 22: 26
LocalVariableTable:
Start Length Slot Name Signature
0 27 0 this LEnclosingClass$1Broom;
}
----------------------EnclosingClass.class--------------------------------
public class EnclosingClass
SourceFile: "EnclosingClass.java"
InnerClasses:
#45= #43; //Broom=class EnclosingClass$1Broom
#48= #46; //ShoppingBag=class EnclosingClass$1ShoppingBag
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Class #2 // EnclosingClass
#2 = Utf8 EnclosingClass
#3 = Class #4 // java/lang/Object
#4 = Utf8 java/lang/Object
#5 = Utf8 numOfTree
#6 = Utf8 I
#7 = Utf8 count
#8 = Utf8 good
#9 = Utf8 Ljava/lang/String;
#10 = Utf8 <clinit>
#11 = Utf8 ()V
#12 = Utf8 Code
#13 = Fieldref #1.#14 // EnclosingClass.count:I
#14 = NameAndType #7:#6 // count:I
#15 = Utf8 LineNumberTable
#16 = Utf8 LocalVariableTable
#17 = Utf8 <init>
#18 = Methodref #3.#19 // java/lang/Object."<init>":()V
#19 = NameAndType #17:#11 // "<init>":()V
#20 = Fieldref #1.#21 // EnclosingClass.numOfTree:I
#21 = NameAndType #5:#6 // numOfTree:I
#22 = String #23 // Das ist gut
#23 = Utf8 Das ist gut
#24 = Fieldref #1.#25 // EnclosingClass.good:Ljava/lang/String;
#25 = NameAndType #8:#9 // good:Ljava/lang/String;
#26 = Utf8 this
#27 = Utf8 LEnclosingClass;
#28 = Utf8 doShopping
#29 = Utf8 num
#30 = Utf8 cleanHouse
#31 = String #32 // Take the broom and start cleaning.
#32 = Utf8 Take the broom and start cleaning.
#33 = Utf8 message
#34 = Utf8 access$0
#35 = Utf8 (LEnclosingClass;)I
#36 = Utf8 access$1
#37 = Utf8 (LEnclosingClass;)Ljava/lang/String;
#38 = Utf8 access$2
#39 = Utf8 ()I
#40 = Utf8 SourceFile
#41 = Utf8 EnclosingClass.java
#42 = Utf8 InnerClasses
#43 = Class #44 // EnclosingClass$1Broom
#44 = Utf8 EnclosingClass$1Broom
#45 = Utf8 Broom
#46 = Class #47 // EnclosingClass$1ShoppingBag
#47 = Utf8 EnclosingClass$1ShoppingBag
#48 = Utf8 ShoppingBag
{
private int numOfTree;
flags: ACC_PRIVATE
private static int count;
flags: ACC_PRIVATE, ACC_STATIC
private java.lang.String good;
flags: ACC_PRIVATE
static {};
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 20
2: putstatic #13 // Field count:I
5: return
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
public EnclosingClass();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #18 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #20 // Field numOfTree:I
10: aload_0
11: ldc #22 // String Das ist gut
13: putfield #24 // Field good:Ljava/lang/String;
16: return
LineNumberTable:
line 2: 0
line 4: 4
line 6: 10
line 2: 16
LocalVariableTable:
Start Length Slot Name Signature
0 17 0 this LEnclosingClass;
public void doShopping();
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=1
0: iconst_3
1: istore_1
2: return
LineNumberTable:
line 9: 0
line 15: 2
LocalVariableTable:
Start Length Slot Name Signature
0 3 0 this LEnclosingClass;
2 1 1 num I
public static void cleanHouse();
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=0
0: ldc #31 // String Take the broom and start cleaning.
2: astore_0
3: return
LineNumberTable:
line 20: 0
line 25: 3
LocalVariableTable:
Start Length Slot Name Signature
3 1 0 message Ljava/lang/String;
static int access$0(EnclosingClass);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #20 // Field numOfTree:I
4: ireturn
LineNumberTable:
line 4: 0
LocalVariableTable:
Start Length Slot Name Signature
static java.lang.String access$1(EnclosingClass);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #24 // Field good:Ljava/lang/String;
4: areturn
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
static int access$2();
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=1, locals=0, args_size=0
0: getstatic #13 // Field count:I
3: ireturn
LineNumberTable:
line 5: 0
LocalVariableTable:
Start Length Slot Name Signature
}
No comments:
Post a Comment