内部类
内部类(inner class) 是定义在另一个类中的类。使用原因如下:
1.内部类方法可以访问该类定义所在的作用域中的数据, 包括私有的数据。
2.内部类可以对同一个包中的其他类隐藏起来。
3.当想要定义一个回调函数且不想编写大量代码时,使用匿名 (anonymous) 内部类比较便捷。
使用内部类访问对象状态
public class TalkingClock
{
private int interval:
private boolean beep;
public TalkingClock(int interval, boolean beep) { . . . }
public void start() { • . . }
public class TimePrinter implements ActionListener
// an inner class
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Oate();)
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
内部类既可以访问自身的数据域,也可以访问创建它的外围类对象的数据域。为了能够运行这个程序, 内部类的对象总有一个隐式引用, 它指向了创建它的外部类对象。
TimePrinter 类声明为私有的。这样一来, 只有 TalkingClock 的方法才能够构造TimePrinter 对象。只有内部类可以是私有类,而常规类只可以具有包可见性,或公有可见性。
内部类的特殊语法规则
使用外围类引用的表达式
OuterClass.this
内部对象的构造器:
outerObject.new InnerClass (construction parameters)
最新构造的 TimePrinter 对象的外围类引用被设置为创建内部类对象的方法中的this 引用。这是一种最常见的情况。通常,this 限定词是多余的。不过,可以通过显式地命名将外围类引用设置为其他的对象。
TalkingClock jabberer = new TalkingClock(1000, true);
TalkingOock.TimePrinter listener = jabberer.new TimePrinter();
在外围类的作用域之外,可以这样引用内部类:
OuterClass.InnerClass
局部内部类
可以在一个方法中定义局部类
public void start() {
class TimePrinter inpleients ActionListener
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the tine is " + new Date());
if (beep) Toolkit.getDefaultToolkit.beep():
}
}
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
局部类不能用 public 或 private 访问说明符进行声明。它的作用域被限定在声明这个局部类的块中。
局部类有一个优势, 即对外部世界可以完全地隐藏起来。 即使 TalkingClock 类中的其他代码也不能访问它。除 start 方法之外, 没有任何方法知道 TimePrinter 类的存在。
匿名内部类
将局部内部类的使用再深人一步。 假如只创建这个类的一个对象,就不必命名了。这种类被称为匿名内部类(anonymous inner class)。
public void start(int interval, boolean beep) {
ActionListener listener = new ActionListenerO
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
};
Timer t = new Timer(interval, listener);
t.start();
}
多年来,Java 程序员习惯的做法是用匿名内部类实现事件监听器和其他回调。如今最好还是使用 lambda 表达式。
public void start(int interval, boolean beep) {
Timer t = new Timer(interval, event -> {
Systea.out.printlnC'At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
});
t.start();
}
下面的技巧称为“ 双括号初始化” (double brace initialization), 这里利用了内部类语法。假设你想构造一个数组列表,并将它传递到一个方法:
ArrayList<String> friends = new ArrayList<>();
friends,add("Harry");
friends,add("Tony");
invite(friends);
如果不再需要这个数组列表,最好让它作为一个匿名列表。
invite(new ArrayList<String>() {{ add("Harry"); add("Tony"); }});
注意这里的双括号。外层括号建立了 ArrayList 的一个匿名子类。内层括号则是一个对象构造块
静态内部类
有时候, 使用内部类只是为了把一个类隐藏在另外一个类的内部,并不需要内部类引用外围类对象。为此,可以将内部类声明为 static, 以便取消产生的引用。
静态内部类的对象除了没有对生成它的外围类对象的引用特权外, 与其他所冇内部类完全一样。
class ArrayAlg{
...
public static class Pair{
...
}
}