使用内部类的优点
内部类是定义在另一个类中的类,使用内部类主要有以下优点
①内部类方法可以访问该类的定义所在的作用域中的数据,包括私有的数据
②内部类可以对同一个包中的其他类隐藏其阿里
③使用匿名内部类比较便捷
使用内部类访问对象状态
package com.javatest;
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 TimerTest {
public static void main(String[] agrs) {
InnerClassTest t = new InnerClassTest(1000 );
t.go();
JOptionPane.showMessageDialog(null, "Quit program?");
System.exit(0);
}
}
class InnerClassTest {
private int interval;
public InnerClassTest(int interval ) {
this.interval = interval;
}
public void go() {
Timer timer = new Timer(interval , new listeneraction());
timer.start();
}
private class listeneraction implements ActionListener{
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("The time is " + new Date());
}
}
}
listeneraction是一个内部类,这个类实现了接口ActionListener中的actionPerformed方法,然后类listeneraction作为实例传入Timer的构造器中,事实上,内部类listeneraction可以访问InnerClassTest 类的实例域,一个内部类可以访问自身的的数据域,也可以访问创建它的外围类对象的数据域。
下面来看这是如何实现,在一个内部类中访问外部类的数据域,为了可以运行这个程序,内部类的对象总是有一个隐式引用,我们假设为Outer(Outer不是java的关键字)。
这个引用在内部类的定义中是不可见的。
局部内部类
public void go() {
class listeneraction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("The time is " + new Date());
if(beep){
Toolkit.getDefaultToolkit().beep();
}
}
Timer timer = new Timer(interval , new listeneraction());
timer.start();
}
上面的例子就是一个局部内部类的例子,注意:局部类不能使用public或者private来修饰。它的作用域已经被限定在声明这个局部类的块中。除了,go方法外,没有任何方法知道listeneraction 的存在 。
局部内部类还有一个优点,它不仅可以访问包含它们的外部类,还可以访问局部变量 看下面的例子
public void go(int interval , boolean beep) {
class listeneraction implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("The time is " + new Date());
if(beep){
Toolkit.getDefaultToolkit().beep();
}
}
}
Timer timer = new Timer(interval , new listeneraction());
timer.start();
}
将类InnerClassTest构造器的参数,interval,beep移动到go方法中。这看起来很正常,类listeneraction 访问beep变量似乎是合情合理的事情,我们思考一下整个的控制流程:调用go方法—>调用内部类listeneraction 的构造器—>将实例化的类对象listeneraction传入Timer构造器,调用stsrt方法,beep变量被释放—>最后,actionPerformed方法执行 if(beep)。从上面的流程中,要使actionPerformed方法可以正常工作,可以看出类listeneraction 在beep域被释放之前用go方法的局部变量进行了备份!
编译器必须检测对局部变量的访问,为每一个变量建立相应的数据域,并将局部变量拷贝到构造器中,以便将这些数据域初始化为局部变量的副本。局部类的方法只可以引用定义为final的局部变量,这样才使得局部变量与在局部类内创建的拷贝的变量保持一致
匿名内部类
假如只创建这个类的一个对象,就不用命名了,这就是匿名内部类。
public void go(int interval , boolean beep) {
Timer timer = new Timer(interval, new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("The time is " + new Date());
if (beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
);
timer.start();
}
创建一个实现ActionListener接口的类的新对象,需要实现的方法actionPerformed定义在{}中。匿名类没有类名,所以不能有构造器。如今,使用匿名内部类还是使用Lambda表达式。