更新时间:2020-08-12 16:17:54 来源:极悦 浏览1823次
What
局部内部类就是定义在某个方法内部的内部类,它的作用域仅限于这个方法。
Why
当我们在外围类中定义的内部类仅仅在某个方法中使用了一次,这种情况下,我们就可以选择去使用局部内部类。
How
以上节课的例子继续讲解,由于TestListener这个内部类仅仅在start方法中使用了一次,所以我们在这里可以使用局部内部类
public class InnerClassTest {
private Integer times;
private boolean beep;
public InnerClassTest(Integer times, boolean beep) {
this.interval = interval;
this.beep = beep;
};
public void start(){
class TestListener implements ActionListner {
public void actionPerformed(ActionEvent event) {
System.out.println("TestListener is running");
if (beep) {
Tookit.getDefaultToolkit().beep();
}
}
}
ActionListener listener = new TestListener();
Timer t = new Timer(times, listner);
t.start();
}
}
这里需要注意,局部类不可以使用public或者private访问修饰符进行声明,因为它作用域仅仅被限定在声明这个局部类的块中。
局部类有一个优势,它可以对外部世界完全的隐藏,即使他的外部类中的其他模块也不可以访问它,除了start方法以外,没有任何方法知道这个内部类的存在。
外部方法访问变量(进阶)
与其他的内部类相比,局部类还有一个其他内部类所不具备的有优点。它不仅可以访问包含它们的外部类,还可以访问局部变量,但是这些局部变量必须声明为final,它们一旦被赋值,就不能被改变。
下面我们接着来改变上面的那个栗子:
public void start(int times, boolean beep){
class TestListener implements ActionListner {
public void actionPerformed(ActionEvent event) {
System.out.println("TestListener is running");
if (flag) {
Tookit.getDefaultToolkit().beep();
}
}
}
ActionListener listener = new TestListener();
Timer t = new Timer(times, listner);
t.start();
}
我们可以看到,外围类不在需要去存储实例变量beep了,它只是引用start方法中的参数。
接下来我们来深入了解这个方法的控制流程:
1.调用start方法
2.调用内部类的构造器,初始化对象变量listener
3.将listener引用传递给Timer构造器,定时器开始计时,start方法结束。此时,start方法中beep变量被回收。
4.然后actionPerformed方法执行if(beep)。
看到这里,我相信大部分人会有疑问,为什么beep变量被回收,但是actionPerformed方法仍然可以调用到这个方法?
实际上,内部类在beep域被释放之前将beep域用start方法中的局部变量进行备份,我们接下来来看一下反编译后的内部类,来证实我们的猜测:
class InnerClassTest$TestListener {
public InnerClass$TestListener(InnerClassTest, boolean);
public void actionPerformed(java.awt.event.ActionEvent);
final boolean val$beep;
final InnerClassTest this$0;
}
请注意构造器的boolean参数和val$beep实例变量。当创建一个对象的时候,beep就会传递给构造器,并存储在val$beep域中。编译器必须检测对局部变量的访问,为每一个变量建立相应的数据域,并将局部变量拷贝到构造器中,以便将这些数据域初始化为局部变量的副本。
匿名内部类
匿名内部类其实就是对局部内部类的一个深化的应用,如果我们只是需要创建这个类的一个对象,那么我们完全不必去给这个类命名,这种类就被称为匿名内部类。
接下来,我们接着对上面的例子进行改编:
public void start(int times, boolean beep){
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent event) {
System.out.println("TestListener is running");
if (flag) {
Tookit.getDefaultToolkit().beep();
}
}
}
Timer t = new Timer(times, listner);
t.start();
}
这段语句的含义是:创建一个实现ActionListener接口的类的新对象,需要实现的方法定义在括号内。
通用的语法格式是:
new SuperType(constrution params) {
inner class methods and data
}
其中SuperType既可以是接口,那么内部类就要去实现这个接口,它同样可以是一个类,那么内部类就要去扩展它。
由于构造器的名字必须与类名相同,但是匿名类并没有类名,所以,匿名类不能有构造器。取而代之的是,将构造器参数传递给父类构造器。尤其是在内部类实现接口的时候,不能有任何构造参数。
如果构造参数的闭小括号后跟的是单引号,那么就是在构造一个类的新对象,如果说构造参数的闭小括号后面跟一个开大括号,正在定义的就是匿名内部类。
静态内部类(仅供了解)
有时候,使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外部类对象。所以可以把内部类声明为static,以便取消产生的引用。
只有内部类可以声明为static,静态内部类的对象除了没有对生成它的外围类对象的引用特权外,与其他所有内部类完全一样。
与常规内部类不同的地方是,静态内部类可以有静态域和方法,声明在接口中的内部类自动生成static和public类。
以上就是极悦java培训机构的小编针对“Java基础学习系列,局部内部类”的内容进行的回答,希望对大家有所帮助,如有疑问,请在线咨询,有专业老师随时为你服务。
0基础 0学费 15天面授
Java就业班有基础 直达就业
业余时间 高薪转行
Java在职加薪班工作1~3年,加薪神器
工作3~5年,晋升架构
提交申请后,顾问老师会电话与您沟通安排学习