CodeGym /Java 课程 /模块 2:Java 核心 /匿名内部类和示例

匿名内部类和示例

模块 2:Java 核心
第 15 级 , 课程 2
可用
匿名内部类和示例 - 1

“嗨,阿米戈!”

“但我们已经打过招呼了,艾莉!”

“喂,你别跟你阿姨吵架,在31世纪,半个小时以上没见人,再打声招呼是习惯性的,所以你别给我态度!”

“总之,又到了另一个有趣的话题了:机器人繁殖!”

“噢噢。”

“开玩笑的,新话题是匿名内部类。”

“在 Java 中,有时会出现需要一个类继承多个类的情况。由于 Java 不支持多重继承,他们使用内部类解决了这个问题:在我们的类中,我们声明一个内部类并使它继承了我们需要它继承的任何类。这是一个例子:“

继承 Thread 类的内部类示例
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对象。

换句话说,我们写了一大堆代码只是为了覆盖一个方法并创建一个对象。

您还记得我是如何谈论构造函数的发明的吗?

在构造函数之前 在构造函数之后
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
Thread thread = new Thread()
{
 public void run()
 {
  tigerRun();
 }
};

“我看到代码变得更紧凑了,但我不太明白发生了什么。”

“我们可以将四件事合而为一:”

1)派生类的声明

2)方法覆盖

3)变量的声明

4) 创建派生类的实例。

“事实上,我们正在做的是结合两个操作:声明派生类和创建该类的实例。”

没有匿名类 使用匿名类
Cat tiger = new Tiger();

class Tiger extends Cat
{
}
Cat tiger = new Cat()
{
};

“让我们再次探讨语法:”

线程变量的声明
Thread thread = new Thread();
类型为“继承 Thread 的匿名类”的变量声明
Thread thread = new Thread()
{

};

“请注意,我们不是简单地定义一个新类。我们正在创建一个变量——末尾有一个分号!”

“如果我们想覆盖运行方法,那么我们需要这样写:”

线程变量的声明
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

“你很快就明白了。干得好!”

“谢谢。如果我们需要其他不属于 Thread 类的方法怎么办?”

“你可以写。”

“虽然是匿名的,但这是一个成熟的内部类:”

Java代码 描述
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};	 
红色:创建变量的代码。

绿色:创建对象的代码。

蓝色:匿名派生类的代码。

“一个完整的内部类?”

“所以我可以使用外部类的变量?”

“绝对地。”

“我可以将一些东西传递给构造函数吗?”

“是的,但只有超类构造函数的参数:”

班级 匿名内部类的实例
class Cat
{
 int x, y;
 Cat(int x, int y)
 {
  this.x = x;
  thix.y = y;
 }
}
Cat cat = new Cat(3,4)
{
  public void print()
  {
   System.out.println(x+" "+y);
  }
};

“我们不能将自己的参数添加到别人的构造函数中。但是我们可以使用外部类的变量,这很好地弥补了这个缺点。”

“如果我真的还需要向构造函数添加其他参数怎么办?”

“然后声明一个普通的(非匿名的)内部类并使用它。”

“对了,我差点忘记了。”

“如果我声明一个静态变量怎么办?这会使匿名类成为静态嵌套类而不是内部类吗?换句话说,它会不会缺少对外部类的引用?”

“不。这将是一个匿名内部类。看看这些例子。”

使用匿名类 没有匿名类
Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
static Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
static TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}

“我明白了。只有静态变量是静态的,类不是。”

“是的。”

“事实上,编译器会为所有匿名内部类创建内部类。这些类通常被命名为 «1»、«2»、«3» 等。”

评论
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION