内部类TimerPrinter实现Actionlistener接口,内部类的对象做计时器Timer的回调对象
public class InnerClassTest{
public static void main(String[] args){
TalkingClock clock = new TalkingClock(1000,true);//创建一个外部类
TalkingClock.TimerPrinter listener = clock.new TimerPrinter();//根据外部类对象创建内部类对象
clock.start();
}
}
class TalkingClock{
private int interval;
private boolen beep;
public TalkingClock(int interval,boolen beep){
this.interval = interval;
this.beep = beep;
}
public void start(){
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval,listener);
t.start();
}
public class TimerPrinter implements ActionListener{
public void actionperformed(ActionEvent e){
Date now = new Data();
System.out.println(now);
if(beep) //TalkingClock.this.beep
Toolkit.getDefaultToolkit().beep();
}
}
}
通过javap反编译内部类
public class TalkingClock$TimePrinter
{
public TalkingClock$TimePrinter(TalkingClock);//外部类对象传入构造函数(编译器隐式生成),给this$0赋值
public void actionPerformed(java.awt.event.ActionEvent);
final TalkingClock this$0;//指向外部类的指针(编译器隐式生成)
}
反编译外部类
class TalkingClock
{
private int interval; private boolean beep;
public TalkingClock(int, boolean);
static boolean access$0(TalkingClock);//编译器自动生成静态方法,提供给内部类访问
public void start();
}
if(beep)等价if(TalkingClock.this.beep)
编译时等价(access$0(outer))
因为非静态内部类要根据外部类的对象创建内部类的实例
TalkingClock clock = new TalkingClock(1000,true);//创建一个外部类对象
TalkingClock.TimerPrinter listener = clock.new TimerPrinter();//根据外部类对象创建内部类对象
所以内部类对象执行actionPerformed时,访问外部对象的private字段时,调用静态方法access$0(outer),访问外部类对象的字段
静态内部类和非静态内部类分别作为静态成员和非静态成员存在于外部类之中
1.
非静态内部类中,不能声明静态方法或变量(但可以调用外部类的)
静态内部类不持有外部类的引用,所以无法访问外部类的非静态成员和方法,可以访问外部类的静态成员,可以有自己的instancefield
2.
非静态内部类依赖于外部类对象而存在,当外部类对象被回收时,它肯定被回收
静态内部类对象不依赖外部类对象而存在,GC时与外部类对象无关
1 内部类是延时加载的,也就是说只会在第一次使用时加载。不使用就不加载,所以可以很好的实现单例模式。
2 不论是静态内部类还是非静态内部类都是在第一次使用时才会被加载。
3 对于非静态内部类是不能出现静态模块(包含静态块,静态属性,静态方法等)
4 非静态类的使用需要依赖于外部类的对象,详见上述对象innerClass 的初始化。
简单来说,类的加载都是发生在类要被用到的时候。内部类也是一样
1 普通内部类在第一次用到时加载,并且每次实例化时都会执行内部成员变量的初始化,以及代码块和构造方法。
2 静态内部类也是在第一次用到时被加载。但是当它加载完以后就会将静态成员变量初始化,运行静态代码块,并且只执行一次。当然,非静态成员和代码块每次实例化时也会执行。
总结一下Java类代码加载的顺序,万变不离其宗。
规律一、初始化构造时,先父后子;只有在父类所有都构造完后子类才被初始化
规律二、类加载先是静态、后非静态、最后是构造函数。
静态构造块、静态类属性按出现在类定义里面的先后顺序初始化,同理非静态的也是一样的,只是静态的只在加载字节码时执行一次,不管你new多少次,非静态会在new多少次就执行多少次
规律三、java中的类只有在被用到的时候才会被加载
规律四、java类只有在类字节码被加载后才可以被构造成对象实例