赞
踩
在 Java 语言中,许多语言层面的细节是无法直接看到的。比如枚举的实现、泛型的擦除、自动拆箱装箱以及本次将说明的内部类的实现。主要原因在于编译器在编译我们的源代码时做了许多的改动,这时需要借助反编译的功能查看都做了哪些改动。在线反编译网站
public class InnerClassType {
class InnerClass {}
}
public class InnerClassType {
Object obj = new Object() {
@Override
public String toString() {
return "Anonymous inner class";
}
};
}
public class InnerClassType {
static class StaticInnerClass {}
}
public static Object anonymousStaticInnerClass = new Object() {
@Override
public String toString() {
return "Anonymous static inner class";
}
};
public void local() {
class LocalInnerClass {}
}
public void local() {
Object anonymousLocalInnerClass = new Object() {
@Override
public String toString() {
return "Anonymous local inner class";
}
};
}
总结下来其实就是作用域与是否为匿名的组合。下面会以局部匿名类为例,其余的情况根据自己写的 Demo 代码通过上面的反编译网站反编译后就可以看到是如何实现的了。
源代码:
public class Printer { private int count; public void print() { } public Printer create(final String msg) { return new Printer() { @Override public void print() { System.out.println(++count + ": " + msg); } }; } }
将 Class 文件反编译后:
public class Printer { private int count; public void print() { } public Printer create(final String msg) { return new Printer$1(this, msg); } // $FF: synthetic method static int access$004(Printer x0) { return ++x0.count; } } class Printer$1 extends Printer { // $FF: synthetic field final String val$msg; // $FF: synthetic field final Printer this$0; Printer$1(final Printer this$0, final String val$msg) { this.this$0 = this$0; this.val$msg = val$msg; } public void print() { System.out.println(Printer.access$004(this.this$0) + ": " + this.val$msg); } }
会发现,编译器会帮我们生成一个继承自源类的局部匿名类的实现类 Preinter$1。来看一下它的构造方法:
Printer$1(final Printer this$0, final String val$msg) {
this.this$0 = this$0;
this.val$msg = val$msg;
}
this$0 为外部类的引用val$msg 为 create 方法的形参 msg实现很简单一目了然。
成员常量。 并且外部类方法的局部变量也必须通过 final 修饰,避免外部方法对变量的修改影响了内部类中维护的相同变量。也就是,当使用了内部类,此时外部类的环境就不允许变更了,但成员数据除外。为什么下面会说到。访问外部类的成员变量与访问外部类的局部变量是不一样的。可以观察一下生成在外部类中的方法 access$004 与 该方法的调用:
static int access$004(Printer x0) {
return ++x0.count;
}
public void print() {
System.out.println(Printer.access$004(this.this$0) + ": " + this.val$msg);
}
最终通过外部类的引用访问外部类的成员变量。思考一下,为什么不像处理局部变量那样处理成员变量呢?不能因为内部类的应用,而强迫使可能会长期驻留主存的、线程共享可读可写的成员数据都具有常量性质。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。