为什么local inner class可以访问的方法参数必须为final

inner class可以分为三种:

1. 定义在class里的普通inner class. 这种inner class可以访问私有变量.

2. 定义在方法里的local inner class. 这种inner class不仅可以访问私有变量, 而且可以访问所在方法的参数, 但这种参数必须为final. 也就是这篇博客要讨论的情况.

3. 定义在方法里的anonymous inner class, 又叫没有名字的local inner class. 这种inner class非常适用于定义callback方法.

 

为什么local inner class可以访问的变量必须定义为final呢? 我们来看一段代码(代码摘自core java, 卷一)

public void start(int interval, final boolean beep) {
		class TimePrinter implements ActionListener {
			public void actionPerformed(ActionEvent event) {
				Date now = new Date();
				System.out.println("At the tone, the time is " + now);
				if (beep)
					Toolkit.getDefaultToolkit().beep();
			}
		}
		ActionListener listener = new TimePrinter();
		Timer t = new Timer(interval, listener);
		t.start();
	}

可以看到, local inner class TimePrinter访问了beep变量. 由于TimePrinter定义的actionPerformed方法是一个listener方法, 这个方法往往是在程序运行时执行的, 也就是说在它被定义的start(...)方法之后执行的. 而在actionPerformed方法被执行的时候, 其实start(int interval, final boolean beep)中的beep变量已经由于start(int interval, final boolean beep)方法执行完毕, 而从它的堆栈中移除了. 所以, local inner class有必要自己保留一份beep的值. 通过查看编译后的inner class文件:

class TalkingClock$1TimePrinter
{
	TalkingClock$1TimePrinter(TalkingClock, boolean);
	public void actionPerformed(java.awt.event.ActionEvent);
	final boolean val$beep;
	final TalkingClock this$0;
}

可以看到, inner class里面所访问的所有对象及变量, 都会被作为参数, 在compiler生成的构造函数中被传入. 这时, beep变量其实相当于在两处被引用了. 一处是start(int interval, final boolean beep), 另一处是inner class的构造函数. 如果beep不是为final的, 那么假如在start(int interval, final boolean beep)方法中可以修改它的值, 就会造成beep的值在start(int interval, final boolean beep)和inner class中不一致的情况. 

 

 

 

 

 

 

你可能感兴趣的:(java,java)