「こんにちは、アミーゴ!」
「でも、もう挨拶したよ、エリー!」
「ねえ、叔母さんと言い争わないでよ。31世紀では、30分以上誰かに会わなかったら、もう一度挨拶するのが通例だよ。だから、そんな態度はやめてよ!」
「とにかく、もう一つの興味深い話題、ロボットの再生の時間です!」
「お、お」
「冗談ですが、新しいトピックは匿名内部クラスです。」
「Java では、複数のクラスを継承するクラスが必要になる場合があります。Java は多重継承をサポートしていないため、内部クラスを使用してこの問題を解決しました。私たちのクラスでは、内部クラスを宣言して make します。継承する必要があるクラスはすべて継承します。例を次に示します。」
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
TigerThread thread = new TigerThread();
thread.start();
}
class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
「別の例を詳しく見てみましょう。」
run メソッドをオーバーライドするには、Thread クラスのサブクラスが必要です。」
「そのため、Tiger クラスでは、Thread を継承し、run メソッドをオーバーライドするTigerThread内部クラスを宣言しました。
「便宜上、Tiger クラスに 2 つのメソッド、tigerRun と startTiger (Thread の run メソッドと start メソッドに似ています) を定義しました。」
「tigerStart メソッドでは、TigerThreadオブジェクトを作成し、その start() メソッドを呼び出します。」
「JVM は、TigerThread のrun メソッドが呼び出されたときに実行を開始する新しいスレッドを作成します。」
「その後、このメソッドは実行メソッドTigerRunを呼び出します。」
「私は以前にスレッドを扱ったことがあるので、これは簡単だと思います。」
「メソッドにtigerRunとtigerStartという名前を付ける必要がありますか?」
「いいえ、これらを run と start と呼ぶこともできましたが、Thread を継承していないことも示したかったのです。説明するとさらにわかりにくくなるかもしれません。」
「OK。それでは、理解できたと思います。しかし、tigerStart が 2 回目に呼び出された場合は、2 番目の Thread オブジェクトを作成して開始します。これは、«1 つの Tiger が 2 つの異なるスレッドで実行される» という意味ではないでしょうか? 」
「まあ、あなたは鋭いですね! あなたは正しいですが、それは良くありません。次のようにコードを書き直しましょう:」
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();
}
}
}
「完全とは言えません。そのようなメソッドを 2 回呼び出すことはできません。しかし、今回は、少なくとも 2 番目のスレッドを作成して、すべてが順調であるかのように見せることはありません。」
「そうです。Tiger を 2 回目に開始するときは、例外が発生します。」
「私はすでにあなたより間違いを見つけるのが上手です、エリー!」
「はい、順調です。それでは匿名の内部クラスに移りましょう。」
「上記のコードのいくつかの側面に注意してください。」
1) Thread クラスを継承しましたが、実際にはコードを実装しませんでした。「それは、「拡張するために継承した」というよりは、「Thread クラスを継承しなければならなかった」ということです。
2) TigerThread オブジェクトは 1 つだけ作成されます。
言い換えれば、1 つのメソッドをオーバーライドして 1 つのオブジェクトを作成するためだけに、大量のコードを作成しました。
私がコンストラクターの発明についてどのように話したか覚えていますか?
コンストラクターの前 | コンストラクターの後 |
---|---|
|
|
「コードがよりコンパクトになったのはわかりますが、何が起こっているのかよくわかりません。」
「4 つのものを 1 つに組み合わせることができます。」
1) 派生クラスの宣言
2) メソッドのオーバーライド
3) 変数の宣言
4) 派生クラスのインスタンスの作成。
「実際、私たちがやっていることは、派生クラスの宣言とそのクラスのインスタンスの作成という 2 つの操作を組み合わせていることです。」
匿名クラスなし | 匿名クラスの場合 |
---|---|
|
|
「もう一度構文を調べてみましょう。」
Thread thread = new Thread();
Thread thread = new Thread()
{
};
「単に新しいクラスを定義しているわけではないことに注意してください。変数を作成しているのです。最後にセミコロンがあります。」
「そして、run メソッドをオーバーライドしたい場合は、次のように記述する必要があります。」
Thread thread = new Thread()
{
public void run()
{
System.out.println("new run-method");
}
};
「すぐに慣れるね。よくやった!」
「ありがとう。Thread クラスの一部ではない他のメソッドが必要な場合はどうすればよいですか?」
「書いてもいいよ。」
「匿名ではありますが、これは本格的な内部クラスです。」
Javaコード | 説明 |
---|---|
|
赤: 変数を作成するコード。
緑: オブジェクトを作成するためのコード。 青: 匿名派生クラスのコード。 |
本格的なインナークラス?
「では、外部クラスの変数を使用できるのでしょうか?」
"絶対。"
「そして、コンストラクターに何かを渡すことはできますか?」
「はい、ただしスーパークラスのコンストラクターの引数のみです。」
クラス | 匿名内部クラスのインスタンス |
---|---|
|
|
「他の人のコンストラクターに独自のパラメーターを追加することはできません。しかし、外部クラスの変数を使用することができ、この欠点をうまく補うことができます。」
「どうしても他のパラメータをコンストラクタに追加する必要がある場合はどうすればよいでしょうか?」
「次に、通常の (匿名でない) 内部クラスを宣言し、それを使用します。」
「そうです、ほとんど忘れていました。」
「静的変数を宣言したらどうなるでしょうか? その場合、匿名クラスは内部クラスではなく静的に入れ子になったクラスになりますか? つまり、外部クラスへの参照がなくなるのでしょうか?」
「いいえ、それは匿名の内部クラスになります。これらの例を見てください。」
匿名クラスの場合 | 匿名クラスなし |
---|---|
|
|
|
|
「なるほど。静的になるのは静的変数だけで、クラスは静的ではありません。」
「はい。」
「実際、コンパイラはすべての匿名内部クラスに対して内部クラスを作成します。これらのクラスには通常、«1»、«2»、«3» などの名前が付けられます。」
GO TO FULL VERSION