“嗨,阿米戈!”
“但我们已经打过招呼了,艾莉!”
“喂,你别跟你阿姨吵架,在31世纪,半个小时以上没见人,再打声招呼是习惯性的,所以你别给我态度!”
“总之,又到了另一个有趣的话题了:机器人繁殖!”
“噢噢。”
“开玩笑的,新话题是匿名内部类。”
“在 Java 中,有时会出现需要一个类继承多个类的情况。由于 Java 不支持多重继承,他们使用内部类解决了这个问题:在我们的类中,我们声明一个内部类并使它继承了我们需要它继承的任何类。这是一个例子:“
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
TigerThread thread = new TigerThread();
thread.start();
}
class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
“让我们深入研究另一个例子:”
我们需要 Thread 类的子类来覆盖它的 run 方法。”
“这就是为什么我们在 Tiger 类中声明了 TigerThread内部类,它继承了 Thread 并重写了 run 方法。
“为了方便,我们在 Tiger 类中定义了两个方法:tigerRun 和 startTiger(类似于 Thread 的 run 和 start 方法)。”
“在 tigerStart 方法中,我们创建了一个TigerThread对象并调用它的 start() 方法。”
“JVM 将创建一个新线程,该线程将在调用TigerThread 的run 方法时开始运行。”
“这个方法然后调用我们的运行方法:tigerRun。”
“我以前使用过线程,所以这看起来很简单。”
“我们必须将方法命名为 tigerRun 和 tigerStart 吗?”
“不,我们可以称它们为 run 和 start,但我也想证明我们没有继承 Thread。解释可能更令人困惑。”
“好的。那么我想我明白了。但是如果第二次调用 tigerStart,我们将创建并启动第二个 Thread 对象。这是否意味着我们将拥有 «一只老虎在两个不同的线程上运行»? “
“好吧,你不是很敏锐吗!你是对的,那可不好。让我们像这样重写代码:”
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
thread.start();
}
private TigerThread thread = new TigerThread();
private class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
“它还不够完美。你仍然不能调用这样的方法两次。但这一次,至少我们不会创建第二个线程,让一切看起来都很好。”
“没错,Tiger第二次启动,你会得到一个异常。”
“我已经比你更善于发现错误了,艾莉!”
“是啊,你做得很好。那让我们继续匿名内部类。”
“请注意上面代码的几个方面:”
1)我们继承了 Thread 类,但实际上没有实现任何代码。“更多的是 «我们必须继承 Thread 类»,而不是 «我们继承它是为了扩展它»。
2)只会创建一个TigerThread对象。
换句话说,我们写了一大堆代码只是为了覆盖一个方法并创建一个对象。
您还记得我是如何谈论构造函数的发明的吗?
在构造函数之前 | 在构造函数之后 |
---|---|
|
|
“我看到代码变得更紧凑了,但我不太明白发生了什么。”
“我们可以将四件事合而为一:”
1)派生类的声明
2)方法覆盖
3)变量的声明
4) 创建派生类的实例。
“事实上,我们正在做的是结合两个操作:声明派生类和创建该类的实例。”
没有匿名类 | 使用匿名类 |
---|---|
|
|
“让我们再次探讨语法:”
Thread thread = new Thread();
Thread thread = new Thread()
{
};
“请注意,我们不是简单地定义一个新类。我们正在创建一个变量——末尾有一个分号!”
“如果我们想覆盖运行方法,那么我们需要这样写:”
Thread thread = new Thread()
{
public void run()
{
System.out.println("new run-method");
}
};
“你很快就明白了。干得好!”
“谢谢。如果我们需要其他不属于 Thread 类的方法怎么办?”
“你可以写。”
“虽然是匿名的,但这是一个成熟的内部类:”
Java代码 | 描述 |
---|---|
|
红色:创建变量的代码。
绿色:创建对象的代码。 蓝色:匿名派生类的代码。 |
“一个完整的内部类?”
“所以我可以使用外部类的变量?”
“绝对地。”
“我可以将一些东西传递给构造函数吗?”
“是的,但只有超类构造函数的参数:”
班级 | 匿名内部类的实例 |
---|---|
|
|
“我们不能将自己的参数添加到别人的构造函数中。但是我们可以使用外部类的变量,这很好地弥补了这个缺点。”
“如果我真的还需要向构造函数添加其他参数怎么办?”
“然后声明一个普通的(非匿名的)内部类并使用它。”
“对了,我差点忘记了。”
“如果我声明一个静态变量怎么办?这会使匿名类成为静态嵌套类而不是内部类吗?换句话说,它会不会缺少对外部类的引用?”
“不。这将是一个匿名内部类。看看这些例子。”
使用匿名类 | 没有匿名类 |
---|---|
|
|
|
|
“我明白了。只有静态变量是静态的,类不是。”
“是的。”
“事实上,编译器会为所有匿名内部类创建内部类。这些类通常被命名为 «1»、«2»、«3» 等。”
GO TO FULL VERSION