java魔法堂_Java魔法堂:内部类详解

一、前言

对于内部类平时编码时使用的场景不多,比较常用的地方应该就是绑定事件处理程序的时候了(从C#、JS转向Java阵营的孩子总不不习惯用匿名内部类来做事件订阅:()。本文将结合Bytecode对四种内部类作介绍,当作一次梳理以便日后查阅。

首先要明确的是内部类是编译器提供的特性,编译器会将含内部类的java文件编译成外部类和内部类的N个文件(N>=2) ,然后JVM就按普通类的方式运行。就如下面的源码会被编译为Outer.class和和Outer$Inner.class文件。

classOuter{classInner{}

}

三、成员内部类

定义在一个类的内部。相对外部类仅有默认和public两种访问修饰符而言,成员内部类可有默认、private、proteced和public四种访问修饰符,效果与成员字段和方法的一样。

示例:

import java.io.*;//Main.java文件

classMain{public static voidmain(String[] args) throws IOException{

MemberCls outer= newMemberCls();

Inner inner1= outer.newInner();

Inner inner2=outer.getInner();

System.out.println(inner1.getVal());

System.out.println(inner2.getVal());

inner1.setVal(2);

System.out.println(inner1.getVal());

System.out.println(inner2.getVal());

inner2.setVal(3);

System.out.println(inner1.getVal());

System.out.println(inner2.getVal());

System.in.read();

}

}//MemberCls.java文件

classMemberCls{private int val = 1;classInner{void setVal(intval){

MemberCls.this.val =val;

}intgetVal(){returnval;

}

}

Inner getInner(){return newInner();

}//运行结果//1//1//2//2//3//3

并生成MemberCls.class和MemberCls$Inner.class两个类文件。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

Classfile /F:/skyDrive/repos/self/jottings/java/sample/01/MemberCls.classLast modified2015-2-3; size 1117bytes

MD5 checksum aea71084f78ab319a339717e4d0e1e79

Compiledfrom "MemberCls.java"

classMemberCls

SourceFile:"MemberCls.java"InnerClasses:

#16= #3 of #5; //Inner=class MemberCls$Inner of class MemberCls

minor version: 0major version:51flags: ACC_SUPER

Constant pool:

#1 = Fieldref #5.#36 //MemberCls.val:I

#2 = Methodref #15.#37 //java/lang/Object."":()V

#3 = Class #38 //MemberCls$Inner

#4 = Methodref #3.#39 //MemberCls$Inner."":(LMemberCls;)V

#5 = Class #40 //MemberCls

#6 = Methodref #5.#37 //MemberCls."":()V

#7 = Methodref #15.#41 //java/lang/Object.getClass:()Ljava/lang/Class;

#8 = Methodref #5.#42 //MemberCls.getInner:()LMemberCls$Inner;

#9 = Fieldref #43.#44 //java/lang/System.out:Ljava/io/PrintStream;

#10 = Methodref #3.#45 //MemberCls$Inner.getVal:()I

#11 = Methodref #46.#47 //java/io/PrintStream.println:(I)V

#12 = Methodref #3.#48 //MemberCls$Inner.setVal:(I)V

#13 = Fieldref #43.#49 //java/lang/System.in:Ljava/io/InputStream;

#14 = Methodref #50.#51 //java/io/InputStream.read:()I

#15 = Class #52 //java/lang/Object

#16 =Utf8 Inner

#17 =Utf8 InnerClasses

#18 =Utf8 val

#19 =Utf8 I

#20 = Utf8 #21 =Utf8 ()V

#22 =Utf8 Code

#23 =Utf8 LineNumberTable

#24 =Utf8 getInner

#25 =Utf8 ()LMemberCls$Inner;

#26 =Utf8 main

#27 = Utf8 ([Ljava/lang/String;)V

#28 =Utf8 Exceptions

#29 = Class #53 //java/io/IOException

#30 = Utf8 access$002#31 =Utf8 (LMemberCls;I)I

#32 = Utf8 access$000#33 =Utf8 (LMemberCls;)I

#34 =Utf8 SourceFile

#35 =Utf8 MemberCls.java

#36 = NameAndType #18:#19 //val:I

#37 = NameAndType #20:#21 //"":()V

#38 =Utf8 MemberCls$Inner

#39 = NameAndType #20:#54 //"":(LMemberCls;)V

#40 =Utf8 MemberCls

#41 = NameAndType #55:#56 //getClass:()Ljava/lang/Class;

#42 = NameAndType #24:#25 //getInner:()LMemberCls$Inner;

#43 = Class #57 //java/lang/System

#44 = NameAndType #58:#59 //out:Ljava/io/PrintStream;

#45 = NameAndType #60:#61 //getVal:()I

#46 = Class #62 //java/io/PrintStream

#47 = NameAndType #63:#64 //println:(I)V

#48 = NameAndType #65:#64 //setVal:(I)V

#49 = NameAndType #66:#67 //in:Ljava/io/InputStream;

#50 = Class #68 //java/io/InputStream

#51 = NameAndType #69:#61 //read:()I

#52 = Utf8 java/lang/Object

#53 = Utf8 java/io/IOException

#54 =Utf8 (LMemberCls;)V

#55 =Utf8 getClass

#56 = Utf8 ()Ljava/lang/Class;

#57 = Utf8 java/lang/System

#58 = Utf8 out#59 = Utf8 Ljava/io/PrintStream;

#60 =Utf8 getVal

#61 =Utf8 ()I

#62 = Utf8 java/io/PrintStream

#63 =Utf8 println

#64 =Utf8 (I)V

#65 =Utf8 setVal

#66 = Utf8 in#67 = Utf8 Ljava/io/InputStream;

#68 = Utf8 java/io/InputStream

#69 =Utf8 read

{

MemberCls();

flags:

Code:

stack=2, locals=1, args_size=1

0: aload_01: invokespecial #2 //Method java/lang/Object."":()V

4: aload_05: iconst_16: putfield #1 //Field val:I

9: returnLineNumberTable:

line2: 0line3: 4line5: 9MemberCls$Inner getInner();

flags:

Code:

stack=3, locals=1, args_size=1

0: new #3 //class MemberCls$Inner

3: dup4: aload_05: invokespecial #4 //Method MemberCls$Inner."":(LMemberCls;)V

8: areturn

LineNumberTable:

line15: 0

public static voidmain(java.lang.String[]) throws java.io.IOException;

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=4, locals=4, args_size=1

0: new #5 //class MemberCls

3: dup4: invokespecial #6 //Method "":()V

7: astore_18: new #3 //class MemberCls$Inner

11: dup12: aload_113: dup14: invokevirtual #7 //Method java/lang/Object.getClass:()Ljava/lang/Class;

17: pop18: invokespecial #4 //Method MemberCls$Inner."":(LMemberCls;)V

21: astore_222: aload_123: invokevirtual #8 //Method getInner:()LMemberCls$Inner;

26: astore_327: getstatic #9 //Field java/lang/System.out:Ljava/io/PrintStream;

30: aload_231: invokevirtual #10 //Method MemberCls$Inner.getVal:()I

34: invokevirtual #11 //Method java/io/PrintStream.println:(I)V

37: getstatic #9 //Field java/lang/System.out:Ljava/io/PrintStream;

40: aload_341: invokevirtual #10 //Method MemberCls$Inner.getVal:()I

44: invokevirtual #11 //Method java/io/PrintStream.println:(I)V

47: aload_248: iconst_249: invokevirtual #12 //Method MemberCls$Inner.setVal:(I)V

52: getstatic #9 //Field java/lang/System.out:Ljava/io/PrintStream;

55: aload_256: invokevirtual #10 //Method MemberCls$Inner.getVal:()I

59: invokevirtual #11 //Method java/io/PrintStream.println:(I)V

62: getstatic #9 //Field java/lang/System.out:Ljava/io/PrintStream;

65: aload_366: invokevirtual #10 //Method MemberCls$Inner.getVal:()I

69: invokevirtual #11 //Method java/io/PrintStream.println:(I)V

72: aload_373: iconst_374: invokevirtual #12 //Method MemberCls$Inner.setVal:(I)V

77: getstatic #9 //Field java/lang/System.out:Ljava/io/PrintStream;

80: aload_281: invokevirtual #10 //Method MemberCls$Inner.getVal:()I

84: invokevirtual #11 //Method java/io/PrintStream.println:(I)V

87: getstatic #9 //Field java/lang/System.out:Ljava/io/PrintStream;

90: aload_391: invokevirtual #10 //Method MemberCls$Inner.getVal:()I

94: invokevirtual #11 //Method java/io/PrintStream.println:(I)V

97: getstatic #13 //Field java/lang/System.in:Ljava/io/InputStream;

100: invokevirtual #14 //Method java/io/InputStream.read:()I

103: pop104: returnLineNumberTable:

line19: 0line20: 8line21: 22line23: 27line24: 37line25: 47line26: 52line27: 62line28: 72line29: 77line30: 87line32: 97line33: 104Exceptions:

throws java.io.IOExceptionstatic int access$002(MemberCls, int);

flags: ACC_STATIC, ACC_SYNTHETIC

Code:

stack=3, locals=2, args_size=2

0: aload_01: iload_12: dup_x13: putfield #1 //Field val:I

6: ireturn

LineNumberTable:

line2: 0

static int access$000(MemberCls);

flags: ACC_STATIC, ACC_SYNTHETIC

Code:

stack=1, locals=1, args_size=1

0: aload_01: getfield #1 //Field val:I

4: ireturn

LineNumberTable:

line2: 0}

MemberCls.class

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

Classfile /F:/skyDrive/repos/self/jottings/java/sample/01/MemberCls$Inner.classLast modified2015-2-3; size 525bytes

MD5 checksum b092ffe3c5b358c786d99d98c104dc40

Compiledfrom "MemberCls.java"

classMemberCls$Inner

SourceFile:"MemberCls.java"InnerClasses:

#25= #5 of #21; //Inner=class MemberCls$Inner of class MemberCls

minor version: 0major version:51flags: ACC_SUPER

Constant pool:

#1 = Fieldref #5.#19 //MemberCls$Inner.this$0:LMemberCls;

#2 = Methodref #6.#20 //java/lang/Object."":()V

#3 = Methodref #21.#22 //MemberCls.access$002:(LMemberCls;I)I

#4 = Methodref #21.#23 //MemberCls.access$000:(LMemberCls;)I

#5 = Class #24 //MemberCls$Inner

#6 = Class #27 //java/lang/Object

#7 = Utf8 this$0#8 =Utf8 LMemberCls;

#9 = Utf8 #10 =Utf8 (LMemberCls;)V

#11 =Utf8 Code

#12 =Utf8 LineNumberTable

#13 =Utf8 setVal

#14 =Utf8 (I)V

#15 =Utf8 getVal

#16 =Utf8 ()I

#17 =Utf8 SourceFile

#18 =Utf8 MemberCls.java

#19 = NameAndType #7:#8 //this$0:LMemberCls;

#20 = NameAndType #9:#28 //"":()V

#21 = Class #29 //MemberCls

#22 = NameAndType #30:#31 //access$002:(LMemberCls;I)I

#23 = NameAndType #32:#33 //access$000:(LMemberCls;)I

#24 =Utf8 MemberCls$Inner

#25 =Utf8 Inner

#26 =Utf8 InnerClasses

#27 = Utf8 java/lang/Object

#28 =Utf8 ()V

#29 =Utf8 MemberCls

#30 = Utf8 access$002#31 =Utf8 (LMemberCls;I)I

#32 = Utf8 access$000#33 =Utf8 (LMemberCls;)I

{

final MemberClsthis$0;

flags: ACC_FINAL, ACC_SYNTHETIC

MemberCls$Inner(MemberCls);

flags:

Code:

stack=2, locals=2, args_size=2

0: aload_01: aload_12: putfield #1 //Field this$0:LMemberCls;

5: aload_06: invokespecial #2 //Method java/lang/Object."":()V

9: returnLineNumberTable:

line5: 0

void setVal(int);

flags:

Code:

stack=2, locals=2, args_size=2

0: aload_01: getfield #1 //Field this$0:LMemberCls;

4: iload_15: invokestatic #3 //Method MemberCls.access$002:(LMemberCls;I)I

8: pop9: returnLineNumberTable:

line7: 0line8: 9

intgetVal();

flags:

Code:

stack=1, locals=1, args_size=1

0: aload_01: getfield #1 //Field this$0:LMemberCls;

4: invokestatic #4 //Method MemberCls.access$000:(LMemberCls;)I

7: ireturn

LineNumberTable:

line10: 0}

MemberCls$Inner.class

由于成员内部类依赖于外部类实例,因此创建内部类实例时要先创建外部类实例,然后通过下列两种形式来创建内部类实例:

//方式一

内部类 内部类实例 = 外部类实例.new内部类();//方式二

外部类{

内部类{}

内部类 get内部类(){return new内部类();

}

}

内部类 内部类实例 = 外部类实例.get内部类();

注意:

1. 当成员内部类拥有与外部类同名的成员变量或方法时,默认是使用成员内部类的成员。若要访问外部类的同名成员,则需要进行如下操作:

外部类.this.成员变量;

外部类.this.成员方法;

2. 对于同一个外部类实例创建的内部类实例,这些内部类实例均操作同一个外部实例。像上述例子那样,均操作同一个val字段。

看Bytecodes可知,编译器自动为MemberCls创建创建两个静态方法access$002和access$000,而MemberCls$Inner实例则通过这两个静态方法访问私有私有字段val的。

//MemberCls.class文件

/** 等价于

* static int setVal(MemberCls outer, int val){

* outer.val = val;

* return val;

* }*/

static int access$002(MemberCls, int);

flags: ACC_STATIC, ACC_SYNTHETIC

Code:

stack=3, locals=2, args_size=2

0: aload_01: iload_12: dup_x13: putfield #1 //Field val:I

6: ireturn

LineNumberTable:

line2: 0

/** 等价于

* static int getVal(MemberCls outer){

* return outer.val;

* }*/

static int access$000(MemberCls);

flags: ACC_STATIC, ACC_SYNTHETIC

Code:

stack=1, locals=1, args_size=1

0: aload_01: getfield #1 //Field val:I

4: ireturn

LineNumberTable:

line2:

//MemberCls$Inner.class文件

/** 等价于

* void setVal(int val){

* MemberCls实例.setVal(val);

* }*/

void setVal(int);

flags:

Code:

stack=2, locals=2, args_size=2

0: aload_01: getfield #1 //Field this$0:LMemberCls;

4: iload_15: invokestatic #3 //Method MemberCls.access$002:(LMemberCls;I)I

8: pop9: returnLineNumberTable:

line7: 0line8: 9

/** 等价于

* int getVal(int val){

* MemberCls实例.getVal();

* }*/

intgetVal();

flags:

Code:

stack=1, locals=1, args_size=1

0: aload_01: getfield #1 //Field this$0:LMemberCls;

4: invokestatic #4 //Method MemberCls.access$000:(LMemberCls;)I

7: ireturn

LineNumberTable:

line10: 0

因此内部类可以访问外部类的所有类型的字段和方法(包括private)。

四、局部内部类

局部内部类定义在方法或某个作用域里面,并且仅限于方法和该作用域内访问。

示例:

import java.io.*;classMain{public static voidmain(String[] args) throws IOException{

LocalCls outer= newLocalCls();

outer.print();

System.in.read();

}

}classLocalCls{private int val = 1;voidprint(){

final String name= "fsjohnhuang";classInner{intgetVal(){returnval;

}void setVal(intval){

LocalCls.this.val =val;

}

String getName(){returnname;

}

}

Inner inner= newInner();

System.out.println(inner.getVal());

inner.setVal(2);

System.out.println(inner.getVal());

System.out.println(inner.getName());

}

}//结果://1//2//fsjohnhuang

生成LocalCls.class和LocalCls$1Inner.class两个类文件。

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

Classfile /F:/skyDrive/repos/self/jottings/java/sample/02/LocalCls.classLast modified2015-2-3; size 1052bytes

MD5 checksum a636f470da37d8c1cb9370dde083d6d8

Compiledfrom "LocalCls.java"

classLocalCls

SourceFile:"LocalCls.java"InnerClasses:

#17= #8; //Inner=class LocalCls$1Inner

minor version: 0major version:51flags: ACC_SUPER

Constant pool:

#1 = Fieldref #3.#36 //LocalCls.val:I

#2 = Methodref #16.#37 //java/lang/Object."":()V

#3 = Class #38 //LocalCls

#4 = Methodref #3.#37 //LocalCls."":()V

#5 = Methodref #3.#39 //LocalCls.print:()V

#6 = Fieldref #40.#41 //java/lang/System.in:Ljava/io/InputStream;

#7 = Methodref #42.#43 //java/io/InputStream.read:()I

#8 = Class #44 //LocalCls$1Inner

#9 = Methodref #8.#45 //LocalCls$1Inner."":(LLocalCls;)V

#10 = Fieldref #40.#46 //java/lang/System.out:Ljava/io/PrintStream;

#11 = Methodref #8.#47 //LocalCls$1Inner.getVal:()I

#12 = Methodref #48.#49 //java/io/PrintStream.println:(I)V

#13 = Methodref #8.#50 //LocalCls$1Inner.setVal:(I)V

#14 = Methodref #8.#51 //LocalCls$1Inner.getName:()Ljava/lang/String;

#15 = Methodref #48.#52 //java/io/PrintStream.println:(Ljava/lang/String;)V

#16 = Class #53 //java/lang/Object

#17 =Utf8 Inner

#18 =Utf8 InnerClasses

#19 =Utf8 val

#20 =Utf8 I

#21 = Utf8 #22 =Utf8 ()V

#23 =Utf8 Code

#24 =Utf8 LineNumberTable

#25 =Utf8 main

#26 = Utf8 ([Ljava/lang/String;)V

#27 =Utf8 Exceptions

#28 = Class #54 //java/io/IOException

#29 =Utf8 print

#30 = Utf8 access$000#31 =Utf8 (LLocalCls;)I

#32 = Utf8 access$002#33 =Utf8 (LLocalCls;I)I

#34 =Utf8 SourceFile

#35 =Utf8 LocalCls.java

#36 = NameAndType #19:#20 //val:I

#37 = NameAndType #21:#22 //"":()V

#38 =Utf8 LocalCls

#39 = NameAndType #29:#22 //print:()V

#40 = Class #55 //java/lang/System

#41 = NameAndType #56:#57 //in:Ljava/io/InputStream;

#42 = Class #58 //java/io/InputStream

#43 = NameAndType #59:#60 //read:()I

#44 =Utf8 LocalCls$1Inner

#45 = NameAndType #21:#61 //"":(LLocalCls;)V

#46 = NameAndType #62:#63 //out:Ljava/io/PrintStream;

#47 = NameAndType #64:#60 //getVal:()I

#48 = Class #65 //java/io/PrintStream

#49 = NameAndType #66:#67 //println:(I)V

#50 = NameAndType #68:#67 //setVal:(I)V

#51 = NameAndType #69:#70 //getName:()Ljava/lang/String;

#52 = NameAndType #66:#71 //println:(Ljava/lang/String;)V

#53 = Utf8 java/lang/Object

#54 = Utf8 java/io/IOException

#55 = Utf8 java/lang/System

#56 = Utf8 in#57 = Utf8 Ljava/io/InputStream;

#58 = Utf8 java/io/InputStream

#59 =Utf8 read

#60 =Utf8 ()I

#61 =Utf8 (LLocalCls;)V

#62 = Utf8 out#63 = Utf8 Ljava/io/PrintStream;

#64 =Utf8 getVal

#65 = Utf8 java/io/PrintStream

#66 =Utf8 println

#67 =Utf8 (I)V

#68 =Utf8 setVal

#69 =Utf8 getName

#70 = Utf8 ()Ljava/lang/String;

#71 = Utf8 (Ljava/lang/String;)V

{

LocalCls();

flags:

Code:

stack=2, locals=1, args_size=1

0: aload_01: invokespecial #2 //Method java/lang/Object."":()V

4: aload_05: iconst_16: putfield #1 //Field val:I

9: returnLineNumberTable:

line3: 0line11: 4

public static voidmain(java.lang.String[]) throws java.io.IOException;

flags: ACC_PUBLIC, ACC_STATIC

Code:

stack=2, locals=2, args_size=1

0: new #3 //class LocalCls

3: dup4: invokespecial #4 //Method "":()V

7: astore_18: aload_19: invokevirtual #5 //Method print:()V

12: getstatic #6 //Field java/lang/System.in:Ljava/io/InputStream;

15: invokevirtual #7 //Method java/io/InputStream.read:()I

18: pop19: returnLineNumberTable:

line5: 0line6: 8line8: 12line9: 19Exceptions:

throws java.io.IOExceptionvoidprint();

flags:

Code:

stack=3, locals=3, args_size=1

0: new #8 //class LocalCls$1Inner

3: dup4: aload_05: invokespecial #9 //Method LocalCls$1Inner."":(LLocalCls;)V

8: astore_29: getstatic #10 //Field java/lang/System.out:Ljava/io/PrintStream;

12: aload_213: invokevirtual #11 //Method LocalCls$1Inner.getVal:()I

16: invokevirtual #12 //Method java/io/PrintStream.println:(I)V

19: aload_220: iconst_221: invokevirtual #13 //Method LocalCls$1Inner.setVal:(I)V

24: getstatic #10 //Field java/lang/System.out:Ljava/io/PrintStream;

27: aload_228: invokevirtual #11 //Method LocalCls$1Inner.getVal:()I

31: invokevirtual #12 //Method java/io/PrintStream.println:(I)V

34: getstatic #10 //Field java/lang/System.out:Ljava/io/PrintStream;

37: aload_238: invokevirtual #14 //Method LocalCls$1Inner.getName:()Ljava/lang/String;

41: invokevirtual #15 //Method java/io/PrintStream.println:(Ljava/lang/String;)V

44: returnLineNumberTable:

line26: 0line27: 9line28: 19line29: 24line30: 34line31: 44

static int access$000(LocalCls);

flags: ACC_STATIC, ACC_SYNTHETIC

Code:

stack=1, locals=1, args_size=1

0: aload_01: getfield #1 //Field val:I

4: ireturn

LineNumberTable:

line3: 0

static int access$002(LocalCls, int);

flags: ACC_STATIC, ACC_SYNTHETIC

Code:

stack=3, locals=2, args_size=2

0: aload_01: iload_12: dup_x13: putfield #1 //Field val:I

6: ireturn

LineNumberTable:

line3: 0}

LocalCls.class

8f900a89c6347c561fdf2122f13be562.png

961ddebeb323a10fe0623af514929fc1.png

Classfile /F:/skyDrive/repos/self/jottings/java/sample/02/LocalCls$1Inner.classLast modified2015-2-3; size 651bytes

MD5 checksum a4bf7c12f15f22b2ebb3f79438a555ab

Compiledfrom "LocalCls.java"

classLocalCls$1Inner

SourceFile:"LocalCls.java"EnclosingMethod: #23.#24 //LocalCls.print

InnerClasses:

#31= #6; //Inner=class LocalCls$1Inner

minor version: 0major version:51flags: ACC_SUPER

Constant pool:

#1 = Fieldref #6.#25 //LocalCls$1Inner.this$0:LLocalCls;

#2 = Methodref #7.#26 //java/lang/Object."":()V

#3 = Methodref #23.#27 //LocalCls.access$000:(LLocalCls;)I

#4 = Methodref #23.#28 //LocalCls.access$002:(LLocalCls;I)I

#5 = String #29 //fsjohnhuang

#6 = Class #30 //LocalCls$1Inner

#7 = Class #33 //java/lang/Object

#8 = Utf8 this$0#9 =Utf8 LLocalCls;

#10 = Utf8 #11 =Utf8 (LLocalCls;)V

#12 =Utf8 Code

#13 =Utf8 LineNumberTable

#14 =Utf8 getVal

#15 =Utf8 ()I

#16 =Utf8 setVal

#17 =Utf8 (I)V

#18 =Utf8 getName

#19 = Utf8 ()Ljava/lang/String;

#20 =Utf8 SourceFile

#21 =Utf8 LocalCls.java

#22 =Utf8 EnclosingMethod

#23 = Class #34 //LocalCls

#24 = NameAndType #35:#36 //print:()V

#25 = NameAndType #8:#9 //this$0:LLocalCls;

#26 = NameAndType #10:#36 //"":()V

#27 = NameAndType #37:#38 //access$000:(LLocalCls;)I

#28 = NameAndType #39:#40 //access$002:(LLocalCls;I)I

#29 =Utf8 fsjohnhuang

#30 =Utf8 LocalCls$1Inner

#31 =Utf8 Inner

#32 =Utf8 InnerClasses

#33 = Utf8 java/lang/Object

#34 =Utf8 LocalCls

#35 =Utf8 print

#36 =Utf8 ()V

#37 = Utf8 access$000#38 =Utf8 (LLocalCls;)I

#39 = Utf8 access$002#40 =Utf8 (LLocalCls;I)I

{

final LocalClsthis$0;

flags: ACC_FINAL, ACC_SYNTHETIC

LocalCls$1Inner(LocalCls);

flags:

Code:

stack=2, locals=2, args_size=2

0: aload_01: aload_12: putfield #1 //Field this$0:LLocalCls;

5: aload_06: invokespecial #2 //Method java/lang/Object."":()V

9: returnLineNumberTable:

line15: 0

intgetVal();

flags:

Code:

stack=1, locals=1, args_size=1

0: aload_01: getfield #1 //Field this$0:LLocalCls;

4: invokestatic #3 //Method LocalCls.access$000:(LLocalCls;)I

7: ireturn

LineNumberTable:

line17: 0

void setVal(int);

flags:

Code:

stack=2, locals=2, args_size=2

0: aload_01: getfield #1 //Field this$0:LLocalCls;

4: iload_15: invokestatic #4 //Method LocalCls.access$002:(LLocalCls;I)I

8: pop9: returnLineNumberTable:

line20: 0line21: 9java.lang.String getName();

flags:

Code:

stack=1, locals=1, args_size=1

0: ldc #5 //String fsjohnhuang

2: areturn

LineNumberTable:

line23: 0}

LocalCls$1Inner.class

上述两个类文件与成员内部类的几乎一模一样,那么就是说内部类作用范围的限制其实是编译器的限制,而不是JVM的限制了。

注意:

1. 不能有public、protected、private和static作修饰;

2. 局部内部类中仅能访问方法或作用域内的常量,若访问的是变量则编译时会出错。

Q:为什么不能访问局部变量呢?

A:假设可以访问局部变量,那么要考虑的是如何引用到局部变量。

首先局部变量是存放在JVM栈帧中的局部变量表中,并且当方法执行完栈帧也随之弹出,也就是说局部变量所占的内存空间是短暂的(不稳定)。

假如局部变量A是基本类型的话,那么数据直接就存放在局部变量表中相应的Slots中,方法执行完就没了。那局部内部类中所访问的局部变量A到底是什么就无从得知了!             假如局部变量A是String类型或其他类类型,那么局部内部类中访问的局部变量A时就有两种方式了,第一种是访问String常量池中该字符串的地址,第二种是指向局部变量A的地址,然后通过变量A去访问String常量池中该字符串。

但上述这些均是在运行时才能决定,而编译时是无法正确地被描述出来。并且由于内部类将被编译成独立的类文件,访问其他类方法的局部变量的操作无法在类文件中描述。而常量则可以在内部类文件的常量池部分中被正确地描述,而JVM中处理时也十分简单高效。类文件的常量池条目将合并到运行时常量池中,因此外部和内部量访问的是同一个常量。

下面的Bytecodes表示内部类中直接将常量池中的常量压栈后作为返回值返回。

java.lang.String getName();

flags:

Code:

stack=1, locals=1, args_size=1

0: ldc #5 //String fsjohnhuang

2: areturn

LineNumberTable:

line23:

五、匿名内部类

匿名内部类其实是局部内部类的特殊形式。一般用来绑定事件监听处理程序上。Android示例:

classOuter{public voidsubs(){

scan_bt.setOnClickListener(newOnClickListener() {

@Overridepublic voidonClick(View v) {//TODO Auto-generated method stub

}

});

}

}

上述代码生成了一个继承OnClickListener类的匿名内部类,然后实例化匿名类的一个实例,然后以该实例作为参数调用setOnClickListener方法。

并生成一个Outer.class和Outer$1.class类文件。

注意事项与局部内部一样。

六、静态内部类

静态内部类定义在类下,只不过多了个关键字static。静态内部类只能访问外部类的静态字段和静态方法。

而实例化静态内部类时只需 new 外部类.静态内部类() 。

七、总结

八、参考

http://www.cnblogs.com/dolphin0520/p/3811445.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值