内部类(inner class)是定义在另一个类中的类。
为什么要使用内部类
- 内部类方法可以访问该类定义所在的作用域中的数据,包括私有的数据。
- 内部类可以对同一个包中的其他类隐藏起来。
- 当想要定义一个回调函数且不想编写大量代码时,使用匿名(anonymous)内部类比较便捷。
使用内部类访问对象状态
内部类的语法比较复杂。鉴于此情况,我们选择一个简单但不太使用的例子说明内部类的使用方法。下面将进一步分析TimerTest示例,并抽象出一个TalkingClock类。构造一个语音时钟时需要提供两个参数:发布通告的间隔和开关铃声的标志。
public class TalkingClock {
private int interval;
private boolean beep;
public TalkingClock(int interval, boolean beep) {....}
public void start() {....};
// 内部类
public class TimePrinter implements ActionListener {
....
}
}
需要注意,这里的TimePrinter类位于TalkingClock类内部。这并不意味着每个TalkingClock都有一个TimePrinter实例域。如前所示,TimePrinter对象由TalkingClock类的方法构造。
下面是TimePrinter类的详细内容。需要注意一点,actionPerformed方法在发出铃声之前检查了beep标志。
public class TimePrinter implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit.beep();
}
}
令人惊讶的事情发生了。TimePrinter类没有实例域或者名为beep的变量,取而代之的是beep引用了创建TimePrinter的TalkingClock对象的域。这是一种创新的想法。从传统意义上讲,一个方法可以引用调用这个方法的对象数据域。内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。
为了能够运行这个程序,内部类的对象总有一个隐式引用,它指向了创建它的外部类对象。
这个引用在内部类的定义中是不可见的。然而,为了说明这个概念,我们将外围类对象的引用称为outer。于是actionPerformed方法等价于:
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Date());
if (outer.beep) Toolkit.getDefaultToolkit().beep();
}
外围类的引用在构造器中设置。编译器修改了所有的内部类的构造器。添加一个外围类引用的参数。因为TimePrinter类没有定义构造器,所以编译器为这个类生成了一个默认的构造器,如:
public TimePrinter(TalkingClock clock) {
outer = clock;
}
请再注意一下,outer不是Java关键字。我们只是用它说明内部类的机制。
当start方法中创建了TimePrinter对象后,编译器就会将this引用传递给当前的语音时钟的构造器:
ActionListener listener = new TimePrinter(this);
实例
package cn.freedompc.innerClass;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.Date;
import javax.swing.JOptionPane;
import javax.swing.Timer;
public class InnerClassTest {
public static void main(String[] args) {
TalkingClock clock = new TalkingClock(1000, true);
clock.start();
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
class TalkingClock {
private int interval;
private boolean beep;
public TalkingClock(int interval, boolean beep) {
this.interval = interval;
this.beep = beep;
}
public void start() {
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
public class TimePrinter implements ActionListener {
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
结果:
捐赠
若你感觉读到这篇文章对你有启发,能引起你的思考。请不要吝啬你的钱包,你的任何打赏或者捐赠都是对我莫大的鼓励。