一、前言                              

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

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

class Outer{
class Inner{}
}

三、成员内部类                        

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

示例:

import java.io.*;
// Main.java文件
class Main{
public static void main(String[] args) throws IOException{
MemberCls outer = new MemberCls();
Inner inner1 = outer.new Inner();
Inner inner2 = outer.getInner(); System.out.println(inner1.getVal());
System.out.println(inner2.getVal());
inner1.setVal();
System.out.println(inner1.getVal());
System.out.println(inner2.getVal());
inner2.setVal();
System.out.println(inner1.getVal());
System.out.println(inner2.getVal()); System.in.read();
}
}
// MemberCls.java文件
class MemberCls{
private int val = ; class Inner{
void setVal(int val){
MemberCls.this.val = val;
}
int getVal(){
return val;
}
} Inner getInner(){
return new Inner();
}
// 运行结果
// 1
// 1
// 2
// 2
// 3
//

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

Classfile /F:/skyDrive/repos/self/jottings/java/sample//MemberCls.class
Last modified --; size bytes
MD5 checksum aea71084f78ab319a339717e4d0e1e79
Compiled from "MemberCls.java"
class MemberCls
SourceFile: "MemberCls.java"
InnerClasses:
#= # of #; //Inner=class MemberCls$Inner of class MemberCls
minor version:
major version:
flags: ACC_SUPER Constant pool:
# = Fieldref #.# // MemberCls.val:I
# = Methodref #.# // java/lang/Object."<init>":()V
# = Class # // MemberCls$Inner
# = Methodref #.# // MemberCls$Inner."<init>":(LMemberCls;)V
# = Class # // MemberCls
# = Methodref #.# // MemberCls."<init>":()V
# = Methodref #.# // java/lang/Object.getClass:()Ljava/lang/Class;
# = Methodref #.# // MemberCls.getInner:()LMemberCls$Inner;
# = Fieldref #.# // java/lang/System.out:Ljava/io/PrintStream;
# = Methodref #.# // MemberCls$Inner.getVal:()I
# = Methodref #.# // java/io/PrintStream.println:(I)V
# = Methodref #.# // MemberCls$Inner.setVal:(I)V
# = Fieldref #.# // java/lang/System.in:Ljava/io/InputStream;
# = Methodref #.# // java/io/InputStream.read:()I
# = Class # // java/lang/Object
# = Utf8 Inner
# = Utf8 InnerClasses
# = Utf8 val
# = Utf8 I
# = Utf8 <init>
# = Utf8 ()V
# = Utf8 Code
# = Utf8 LineNumberTable
# = Utf8 getInner
# = Utf8 ()LMemberCls$Inner;
# = Utf8 main
# = Utf8 ([Ljava/lang/String;)V
# = Utf8 Exceptions
# = Class # // java/io/IOException
# = Utf8 access$
# = Utf8 (LMemberCls;I)I
# = Utf8 access$
# = Utf8 (LMemberCls;)I
# = Utf8 SourceFile
# = Utf8 MemberCls.java
# = NameAndType #:# // val:I
# = NameAndType #:# // "<init>":()V
# = Utf8 MemberCls$Inner
# = NameAndType #:# // "<init>":(LMemberCls;)V
# = Utf8 MemberCls
# = NameAndType #:# // getClass:()Ljava/lang/Class;
# = NameAndType #:# // getInner:()LMemberCls$Inner;
# = Class # // java/lang/System
# = NameAndType #:# // out:Ljava/io/PrintStream;
# = NameAndType #:# // getVal:()I
# = Class # // java/io/PrintStream
# = NameAndType #:# // println:(I)V
# = NameAndType #:# // setVal:(I)V
# = NameAndType #:# // in:Ljava/io/InputStream;
# = Class # // java/io/InputStream
# = NameAndType #:# // read:()I
# = Utf8 java/lang/Object
# = Utf8 java/io/IOException
# = Utf8 (LMemberCls;)V
# = Utf8 getClass
# = Utf8 ()Ljava/lang/Class;
# = Utf8 java/lang/System
# = Utf8 out
# = Utf8 Ljava/io/PrintStream;
# = Utf8 getVal
# = Utf8 ()I
# = Utf8 java/io/PrintStream
# = Utf8 println
# = Utf8 (I)V
# = Utf8 setVal
# = Utf8 in
# = Utf8 Ljava/io/InputStream;
# = Utf8 java/io/InputStream
# = Utf8 read
{
MemberCls();
flags: Code:
stack=, locals=, args_size=
: aload_0
: invokespecial # // Method java/lang/Object."<init>":()V
: aload_0
: iconst_1
: putfield # // Field val:I
: return
LineNumberTable:
line :
line :
line : MemberCls$Inner getInner();
flags: Code:
stack=, locals=, args_size=
: new # // class MemberCls$Inner
: dup
: aload_0
: invokespecial # // Method MemberCls$Inner."<init>":(LMemberCls;)V
: areturn
LineNumberTable:
line : public static void main(java.lang.String[]) throws java.io.IOException;
flags: ACC_PUBLIC, ACC_STATIC Code:
stack=, locals=, args_size=
: new # // class MemberCls
: dup
: invokespecial # // Method "<init>":()V
: astore_1
: new # // class MemberCls$Inner
: dup
: aload_1
: dup
: invokevirtual # // Method java/lang/Object.getClass:()Ljava/lang/Class;
: pop
: invokespecial # // Method MemberCls$Inner."<init>":(LMemberCls;)V
: astore_2
: aload_1
: invokevirtual # // Method getInner:()LMemberCls$Inner;
: astore_3
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_2
: invokevirtual # // Method MemberCls$Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_3
: invokevirtual # // Method MemberCls$Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: aload_2
: iconst_2
: invokevirtual # // Method MemberCls$Inner.setVal:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_2
: invokevirtual # // Method MemberCls$Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_3
: invokevirtual # // Method MemberCls$Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: aload_3
: iconst_3
: invokevirtual # // Method MemberCls$Inner.setVal:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_2
: invokevirtual # // Method MemberCls$Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_3
: invokevirtual # // Method MemberCls$Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: getstatic # // Field java/lang/System.in:Ljava/io/InputStream;
: invokevirtual # // Method java/io/InputStream.read:()I
: pop
: return
LineNumberTable:
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
line :
Exceptions:
throws java.io.IOException static int access$(MemberCls, int);
flags: ACC_STATIC, ACC_SYNTHETIC Code:
stack=, locals=, args_size=
: aload_0
: iload_1
: dup_x1
: putfield # // Field val:I
: ireturn
LineNumberTable:
line : static int access$(MemberCls);
flags: ACC_STATIC, ACC_SYNTHETIC Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field val:I
: ireturn
LineNumberTable:
line :
}

MemberCls.class

Classfile /F:/skyDrive/repos/self/jottings/java/sample//MemberCls$Inner.class
Last modified --; size bytes
MD5 checksum b092ffe3c5b358c786d99d98c104dc40
Compiled from "MemberCls.java"
class MemberCls$Inner
SourceFile: "MemberCls.java"
InnerClasses:
#= # of #; //Inner=class MemberCls$Inner of class MemberCls
minor version:
major version:
flags: ACC_SUPER Constant pool:
# = Fieldref #.# // MemberCls$Inner.this$0:LMemberCls;
# = Methodref #.# // java/lang/Object."<init>":()V
# = Methodref #.# // MemberCls.access$002:(LMemberCls;I)I
# = Methodref #.# // MemberCls.access$000:(LMemberCls;)I
# = Class # // MemberCls$Inner
# = Class # // java/lang/Object
# = Utf8 this$
# = Utf8 LMemberCls;
# = Utf8 <init>
# = Utf8 (LMemberCls;)V
# = Utf8 Code
# = Utf8 LineNumberTable
# = Utf8 setVal
# = Utf8 (I)V
# = Utf8 getVal
# = Utf8 ()I
# = Utf8 SourceFile
# = Utf8 MemberCls.java
# = NameAndType #:# // this$0:LMemberCls;
# = NameAndType #:# // "<init>":()V
# = Class # // MemberCls
# = NameAndType #:# // access$002:(LMemberCls;I)I
# = NameAndType #:# // access$000:(LMemberCls;)I
# = Utf8 MemberCls$Inner
# = Utf8 Inner
# = Utf8 InnerClasses
# = Utf8 java/lang/Object
# = Utf8 ()V
# = Utf8 MemberCls
# = Utf8 access$
# = Utf8 (LMemberCls;I)I
# = Utf8 access$
# = Utf8 (LMemberCls;)I
{
final MemberCls this$;
flags: ACC_FINAL, ACC_SYNTHETIC MemberCls$Inner(MemberCls);
flags: Code:
stack=, locals=, args_size=
: aload_0
: aload_1
: putfield # // Field this$0:LMemberCls;
: aload_0
: invokespecial # // Method java/lang/Object."<init>":()V
: return
LineNumberTable:
line : void setVal(int);
flags: Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field this$0:LMemberCls;
: iload_1
: invokestatic # // Method MemberCls.access$002:(LMemberCls;I)I
: pop
: return
LineNumberTable:
line :
line : int getVal();
flags: Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field this$0:LMemberCls;
: invokestatic # // Method MemberCls.access$000:(LMemberCls;)I
: ireturn
LineNumberTable:
line :
}

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$(MemberCls, int);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=, locals=, args_size=
: aload_0
: iload_1
: dup_x1
: putfield # // Field val:I
: ireturn
LineNumberTable:
line : /** 等价于
* static int getVal(MemberCls outer){
* return outer.val;
* }
*/
static int access$(MemberCls);
flags: ACC_STATIC, ACC_SYNTHETIC
Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field val:I
: ireturn
LineNumberTable:
line :
// MemberCls$Inner.class文件

/** 等价于
* void setVal(int val){
* MemberCls实例.setVal(val);
* }
*/
void setVal(int);
flags:
Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field this$0:LMemberCls;
: iload_1
: invokestatic # // Method MemberCls.access$002:(LMemberCls;I)I
: pop
: return
LineNumberTable:
line :
line : /** 等价于
* int getVal(int val){
* MemberCls实例.getVal();
* }
*/
int getVal();
flags:
Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field this$0:LMemberCls;
: invokestatic # // Method MemberCls.access$000:(LMemberCls;)I
: ireturn
LineNumberTable:
line :

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

四、局部内部类                           

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

示例:

import java.io.*;

class Main{
public static void main(String[] args) throws IOException{
LocalCls outer = new LocalCls();
outer.print(); System.in.read();
}
} class LocalCls{
private int val = ; void print(){
final String name = "fsjohnhuang";
class Inner{
int getVal(){
return val;
}
void setVal(int val){
LocalCls.this.val = val;
}
String getName(){
return name;
}
} Inner inner = new Inner();
System.out.println(inner.getVal());
inner.setVal();
System.out.println(inner.getVal());
System.out.println(inner.getName());
}
}
// 结果:
// 1
// 2
// fsjohnhuang

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

Classfile /F:/skyDrive/repos/self/jottings/java/sample//LocalCls.class
Last modified --; size bytes
MD5 checksum a636f470da37d8c1cb9370dde083d6d8
Compiled from "LocalCls.java"
class LocalCls
SourceFile: "LocalCls.java"
InnerClasses:
#= #; //Inner=class LocalCls$1Inner
minor version:
major version:
flags: ACC_SUPER Constant pool:
# = Fieldref #.# // LocalCls.val:I
# = Methodref #.# // java/lang/Object."<init>":()V
# = Class # // LocalCls
# = Methodref #.# // LocalCls."<init>":()V
# = Methodref #.# // LocalCls.print:()V
# = Fieldref #.# // java/lang/System.in:Ljava/io/InputStream;
# = Methodref #.# // java/io/InputStream.read:()I
# = Class # // LocalCls$1Inner
# = Methodref #.# // LocalCls$1Inner."<init>":(LLocalCls;)V
# = Fieldref #.# // java/lang/System.out:Ljava/io/PrintStream;
# = Methodref #.# // LocalCls$1Inner.getVal:()I
# = Methodref #.# // java/io/PrintStream.println:(I)V
# = Methodref #.# // LocalCls$1Inner.setVal:(I)V
# = Methodref #.# // LocalCls$1Inner.getName:()Ljava/lang/String;
# = Methodref #.# // java/io/PrintStream.println:(Ljava/lang/String;)V
# = Class # // java/lang/Object
# = Utf8 Inner
# = Utf8 InnerClasses
# = Utf8 val
# = Utf8 I
# = Utf8 <init>
# = Utf8 ()V
# = Utf8 Code
# = Utf8 LineNumberTable
# = Utf8 main
# = Utf8 ([Ljava/lang/String;)V
# = Utf8 Exceptions
# = Class # // java/io/IOException
# = Utf8 print
# = Utf8 access$
# = Utf8 (LLocalCls;)I
# = Utf8 access$
# = Utf8 (LLocalCls;I)I
# = Utf8 SourceFile
# = Utf8 LocalCls.java
# = NameAndType #:# // val:I
# = NameAndType #:# // "<init>":()V
# = Utf8 LocalCls
# = NameAndType #:# // print:()V
# = Class # // java/lang/System
# = NameAndType #:# // in:Ljava/io/InputStream;
# = Class # // java/io/InputStream
# = NameAndType #:# // read:()I
# = Utf8 LocalCls$1Inner
# = NameAndType #:# // "<init>":(LLocalCls;)V
# = NameAndType #:# // out:Ljava/io/PrintStream;
# = NameAndType #:# // getVal:()I
# = Class # // java/io/PrintStream
# = NameAndType #:# // println:(I)V
# = NameAndType #:# // setVal:(I)V
# = NameAndType #:# // getName:()Ljava/lang/String;
# = NameAndType #:# // println:(Ljava/lang/String;)V
# = Utf8 java/lang/Object
# = Utf8 java/io/IOException
# = Utf8 java/lang/System
# = Utf8 in
# = Utf8 Ljava/io/InputStream;
# = Utf8 java/io/InputStream
# = Utf8 read
# = Utf8 ()I
# = Utf8 (LLocalCls;)V
# = Utf8 out
# = Utf8 Ljava/io/PrintStream;
# = Utf8 getVal
# = Utf8 java/io/PrintStream
# = Utf8 println
# = Utf8 (I)V
# = Utf8 setVal
# = Utf8 getName
# = Utf8 ()Ljava/lang/String;
# = Utf8 (Ljava/lang/String;)V
{
LocalCls();
flags: Code:
stack=, locals=, args_size=
: aload_0
: invokespecial # // Method java/lang/Object."<init>":()V
: aload_0
: iconst_1
: putfield # // Field val:I
: return
LineNumberTable:
line :
line : public static void main(java.lang.String[]) throws java.io.IOException;
flags: ACC_PUBLIC, ACC_STATIC Code:
stack=, locals=, args_size=
: new # // class LocalCls
: dup
: invokespecial # // Method "<init>":()V
: astore_1
: aload_1
: invokevirtual # // Method print:()V
: getstatic # // Field java/lang/System.in:Ljava/io/InputStream;
: invokevirtual # // Method java/io/InputStream.read:()I
: pop
: return
LineNumberTable:
line :
line :
line :
line :
Exceptions:
throws java.io.IOException void print();
flags: Code:
stack=, locals=, args_size=
: new # // class LocalCls$1Inner
: dup
: aload_0
: invokespecial # // Method LocalCls$1Inner."<init>":(LLocalCls;)V
: astore_2
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_2
: invokevirtual # // Method LocalCls$1Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: aload_2
: iconst_2
: invokevirtual # // Method LocalCls$1Inner.setVal:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_2
: invokevirtual # // Method LocalCls$1Inner.getVal:()I
: invokevirtual # // Method java/io/PrintStream.println:(I)V
: getstatic # // Field java/lang/System.out:Ljava/io/PrintStream;
: aload_2
: invokevirtual # // Method LocalCls$1Inner.getName:()Ljava/lang/String;
: invokevirtual # // Method java/io/PrintStream.println:(Ljava/lang/String;)V
: return
LineNumberTable:
line :
line :
line :
line :
line :
line : static int access$(LocalCls);
flags: ACC_STATIC, ACC_SYNTHETIC Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field val:I
: ireturn
LineNumberTable:
line : static int access$(LocalCls, int);
flags: ACC_STATIC, ACC_SYNTHETIC Code:
stack=, locals=, args_size=
: aload_0
: iload_1
: dup_x1
: putfield # // Field val:I
: ireturn
LineNumberTable:
line :
}

LocalCls.class

Classfile /F:/skyDrive/repos/self/jottings/java/sample//LocalCls$1Inner.class
Last modified --; size bytes
MD5 checksum a4bf7c12f15f22b2ebb3f79438a555ab
Compiled from "LocalCls.java"
class LocalCls$1Inner
SourceFile: "LocalCls.java"
EnclosingMethod: #.# // LocalCls.print
InnerClasses:
#= #; //Inner=class LocalCls$1Inner
minor version:
major version:
flags: ACC_SUPER Constant pool:
# = Fieldref #.# // LocalCls$1Inner.this$0:LLocalCls;
# = Methodref #.# // java/lang/Object."<init>":()V
# = Methodref #.# // LocalCls.access$000:(LLocalCls;)I
# = Methodref #.# // LocalCls.access$002:(LLocalCls;I)I
# = String # // fsjohnhuang
# = Class # // LocalCls$1Inner
# = Class # // java/lang/Object
# = Utf8 this$
# = Utf8 LLocalCls;
# = Utf8 <init>
# = Utf8 (LLocalCls;)V
# = Utf8 Code
# = Utf8 LineNumberTable
# = Utf8 getVal
# = Utf8 ()I
# = Utf8 setVal
# = Utf8 (I)V
# = Utf8 getName
# = Utf8 ()Ljava/lang/String;
# = Utf8 SourceFile
# = Utf8 LocalCls.java
# = Utf8 EnclosingMethod
# = Class # // LocalCls
# = NameAndType #:# // print:()V
# = NameAndType #:# // this$0:LLocalCls;
# = NameAndType #:# // "<init>":()V
# = NameAndType #:# // access$000:(LLocalCls;)I
# = NameAndType #:# // access$002:(LLocalCls;I)I
# = Utf8 fsjohnhuang
# = Utf8 LocalCls$1Inner
# = Utf8 Inner
# = Utf8 InnerClasses
# = Utf8 java/lang/Object
# = Utf8 LocalCls
# = Utf8 print
# = Utf8 ()V
# = Utf8 access$
# = Utf8 (LLocalCls;)I
# = Utf8 access$
# = Utf8 (LLocalCls;I)I
{
final LocalCls this$;
flags: ACC_FINAL, ACC_SYNTHETIC LocalCls$1Inner(LocalCls);
flags: Code:
stack=, locals=, args_size=
: aload_0
: aload_1
: putfield # // Field this$0:LLocalCls;
: aload_0
: invokespecial # // Method java/lang/Object."<init>":()V
: return
LineNumberTable:
line : int getVal();
flags: Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field this$0:LLocalCls;
: invokestatic # // Method LocalCls.access$000:(LLocalCls;)I
: ireturn
LineNumberTable:
line : void setVal(int);
flags: Code:
stack=, locals=, args_size=
: aload_0
: getfield # // Field this$0:LLocalCls;
: iload_1
: invokestatic # // Method LocalCls.access$002:(LLocalCls;I)I
: pop
: return
LineNumberTable:
line :
line : java.lang.String getName();
flags: Code:
stack=, locals=, args_size=
: ldc # // String fsjohnhuang
: areturn
LineNumberTable:
line :
}

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=, locals=, args_size=
: ldc # // String fsjohnhuang
: areturn
LineNumberTable:
line :

五、匿名内部类                          

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

class Outer{
public void subs(){
scan_bt.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub }
});
}
}

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

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

六、静态内部类                          

静态内部类定义在类下,只不过多了个关键字static。静态内部类只能访问外部类的静态字段和静态方法。
  而实例化静态内部类时只需 new 外部类.静态内部类() 。

七、总结                            

尊重原创,转载请注明来自:http://www.cnblogs.com/fsjohnhuang/p/4270044.html  ^_^肥仔John

八、参考                            

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

Java魔法堂:内部类详解的更多相关文章

  1. java四种内部类详解

    一般来说,有4中内部类:常规内部类.静态内部类.局部内部类.匿名内部类. 一.常规内部类:常规内部类没有用static修饰且定义在在外部类类体中.   1.常规内部类中的方法可以直接使用外部类的实例变 ...

  2. Java基础(54):java四种内部类详解(转)

    一般来说,有4中内部类:常规内部类.静态内部类.局部内部类.匿名内部类.  一.常规内部类:常规内部类没有用static修饰且定义在在外部类类体中. 1.常规内部类中的方法可以直接使用外部类的实例变量 ...

  3. java中的内部类详解

    https://www.cnblogs.com/dolphin0520/p/3811445.html https://www.cnblogs.com/chenssy/p/3388487.html

  4. 【转】Java魔法堂:String.format详解

    Java魔法堂:String.format详解     目录     一.前言    二.重载方法     三.占位符     四.对字符.字符串进行格式化     五.对整数进行格式化     六. ...

  5. Java内部类详解

    Java内部类详解 说起内部类这个词,想必很多人都不陌生,但是又会觉得不熟悉.原因是平时编写代码时可能用到的场景不多,用得最多的是在有事件监听的情况下,并且即使用到也很少去总结内部类的用法.今天我们就 ...

  6. [转] Java内部类详解

    作者:海子 出处:http://www.cnblogs.com/dolphin0520/ 本博客中未标明转载的文章归作者海子和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置 ...

  7. JAVA基础——内部类详解

    JAVA内部类详解 在我的另一篇java三大特性的封装中讲到java内部类的简单概要,这里将详细深入了解java内部类的使用和应用. 我们知道内部类可分为以下几种: 成员内部类 静态内部类 方法内部类 ...

  8. 【转】Java内部类详解

    一.内部类基础 在Java中,可以将一个类定义在另一个类里面或者一个方法里面,这样的类称为内部类.广泛意义上的内部类一般来说包括这四种:成员内部类.局部内部类.匿名内部类和静态内部类.下面就先来了解一 ...

  9. Java内部类详解(一)

    (转自:http://blog.csdn.net/wangpeng047/article/details/12344593) 很多人对于Java内部类(Inner Class)都十分陌生,甚至听都没听 ...

  10. “全栈2019”Java第九十六章:抽象局部内部类详解

    难度 初级 学习时间 10分钟 适合人群 零基础 开发语言 Java 开发环境 JDK v11 IntelliJ IDEA v2018.3 文章原文链接 "全栈2019"Java第 ...

随机推荐

  1. goalng 发布的版本中自动加上 git revision

    概述 起因是这样的,在编译发布 golang 工程时,希望版本号中包含有 git revision number. 但是,没有commit之前,是没法知道 revision number 的,comm ...

  2. 使用call来实现继承

    function Class1(arg1,arg2) { this.name = arg1; this.pass = arg2; this.showSub = function() { return ...

  3. Windows Azure 服务器时间问题

    最近一直在做学校的一个小项目,前期在没有服务器端的情况下意淫做出来了手机客户端.在寒假里使用ASP.NET快速做了一个网站并且设计好了需要使用其他内容,在Windows Azure上测试评估,为学校的 ...

  4. MySql学习(MariaDb)

    资料 http://www.cnblogs.com/lyhabc/p/3691555.html http://www.cnblogs.com/lyhabc/p/3691555.html MariaDb ...

  5. JavaScript使用DeviceOne开发实战(一) 配置和起步

    2015 年 9 月 底,DeviceOne Release发布.至此,DeviceOne 基本完成了对多端的支持.基于 DeviceOne 可以: HTML5.Android.iOS.Windows ...

  6. BIT祝威博客汇总(Blog Index)

    +BIT祝威+悄悄在此留下版了个权的信息说: 关于硬件(Hardware) <穿越计算机的迷雾>笔记 继电器是如何成为CPU的(1) 继电器是如何成为CPU的(2) 关于操作系统(Oper ...

  7. Java枚举类型getClass和getDeclaringClass区别(未完待续)

    Java中的枚举类型有getClass()和getDeclaringClass()两个方法,在通常情况下这两个方法返回的类型一样,在某些场景下会有不同的表现 参照 http://stackoverfl ...

  8. 微软Edge 内嵌的JavaScript 引擎即将开源

    微软于今日(2015年12月10日)宣布即将开源Chakra核心控件,并改名为“ChakraCore”,该控件包含所有Edge JavaScript 引擎的所有核心功能.ChakraCore 将于下月 ...

  9. iOS Crash常规跟踪方法及Bugly集成运用

    当app出现崩溃, 研发阶段一般可以通过以下方式来跟踪crash信息 #1.模拟器运行, 查看xcode错误日志 #2.真机调试, 查看xcode错误日志 #3.真机运行, 查看device系统日志 ...

  10. Ghost博客安装

    Ghost博客是一个基于Node.js 的开源博客平台,由前WordPress UI 部门主管John O'Nolan 和WordPress 高级工程师Hannah Wolfe 创立,目的是为了给用户 ...