Java内部类与代理机制深度解析
立即解锁
发布时间: 2025-08-18 00:07:22 阅读量: 2 订阅数: 11 

### Java 内部类与代理机制深度解析
#### 1. 局部内部类
在某些情况下,我们在代码中可能仅在一处使用某个类的名称。例如在 `TalkingClock` 示例中,`TimePrinter` 类型的名称仅在 `start` 方法里创建该类型对象时使用了一次。这种情况下,我们可以在单个方法内局部定义这个类。
```java
public void start()
{
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();
}
}
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
```
局部类有以下特点:
- 不会使用访问修饰符(如 `public` 或 `private`)进行声明。
- 其作用域仅限于声明它的代码块。
- 最大的优势是对外部世界完全隐藏,即使是 `TalkingClock` 类中的其他代码也无法访问它。除了 `start` 方法,没有其他方法知道 `TimePrinter` 类的存在。
#### 2. 访问外部方法的变量
局部类相较于其他内部类还有一个优势,它不仅可以访问外部类的字段,还能访问局部变量。不过,这些局部变量必须是有效的 `final` 变量,即一旦赋值就不能再改变。
以下是一个典型示例,将 `interval` 和 `beep` 参数从 `TalkingClock` 构造函数移到 `start` 方法中:
```java
public void start(int interval, boolean beep)
{
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();
}
}
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
```
这里 `TalkingClock` 类不再需要存储 `beep` 实例字段,而是直接引用 `start` 方法的 `beep` 参数变量。
控制流程分析如下:
1. 调用 `start` 方法。
2. 通过调用内部类 `TimePrinter` 的构造函数初始化对象变量 `listener`。
3. 将 `listener` 引用传递给 `Timer` 构造函数,启动定时器,`start` 方法退出。此时,`start` 方法的 `beep` 参数变量已不存在。
4. 一秒后,`actionPerformed` 方法执行 `if (beep) ...`。
为了让 `actionPerformed` 方法中的代码正常工作,`TimePrinter` 类必须在 `beep` 参数值消失之前,将 `beep` 字段复制为 `start` 方法的局部变量。实际上就是这样,编译器会为局部内部类合成名称,如 `TalkingClock$1TimePrinter`。
如果使用 `ReflectionTest` 程序查看 `TalkingClock$1TimePrinter` 类,会得到以下输出:
```java
class TalkingClock$1TimePrinter
{
TalkingClock$1TimePrinter(TalkingClock, boolean);
public void actionPerformed(java.awt.event.ActionEvent);
final boolean val$beep;
final TalkingClock this$0;
}
```
从程序员的角度看,访问局部变量很方便,它通过减少需要显式编程的实例字段,使内部类更简单。
需要注意的是,局部类的方法只能引用声明为 `final` 的局部变量。在 Java SE 8 之前,从局部类访问的任何局部变量都必须声明为 `final`。例如:
```java
public void start(int interval, final boolean beep)
```
“有效 `final`” 限制有时不太方便。例如,想要更新封闭作用域中的计数器:
```java
int counter = 0;
Date[] dates = new Date[100];
for (int i = 0; i < dates.length; i++)
dates[i] = new Date()
{
public int compareTo(Date other)
{
counter++; // Error
return super.compareTo(other);
}
};
Arrays.sort(dates);
System.out.println(counter + " comparisons.");
```
由于需要更新 `counter`,不能将其声明为 `final`,也不能用 `Integer` 替换,因为 `Integer` 对象是不可变的。解决方法是使用长度为 1 的数组:
```java
int[] counter = new int[1];
for (int i = 0; i < dates.length; i++)
dates[i] = new Date()
{
public int compareTo(Date other)
{
counter[0]++;
return super.compareTo(other);
}
};
```
#### 3. 匿名内部类
使用局部内部类时,若只想创建该类的单个对象,甚至无需给类命名,这样的类称为匿名内部类。
```java
public void start(int interval, boolean beep)
{
ActionListener listener = new ActionListener()
{
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();
}
```
这种语法比较晦涩,其含义是创建一个实现 `ActionListener` 接口的新类对象,`actionPerformed` 方法在花括号内定义。
一般语法如下:
```java
new SuperType(construction parameters)
{
inner class methods and data
}
```
其中,`SuperType` 可以是接口(如 `ActionListener`),此时内部类实现该接口;也可以是类,此时内部类继承该类。
匿名内部类不能有构造函数,因为构造函数的名称必须与类名相同,而该类没有名称。相反,构造参数会传递给超类的构造函数。特别是当内部类实现接口时,不能有任何构造参数,但仍需提供一对括号。
以下是创建普通类对象和匿名内部类对象的区别示例:
```java
Person queen = new Person("Mary"); // a Person object
Person count = new Person("Dracula") { ... }; // an object of an inner class extending Person
```
如果构造参数列表的右括号后面跟着左花括号,则表示正在定义一个匿名内部类。
匿名内部类的完整示例代码如下:
```java
package anonymousInnerClass;
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
/**
* This program demonstrates anonymous inner classes.
* @version 1.11 2015-05-12
* @author Cay Horstmann
*/
public class AnonymousInnerClassTest
{
public static void main(String[] args)
{
TalkingClock clock = new TalkingClock();
clock.start(1000, true
```
0
0
复制全文
相关推荐









