[ Java Gold 対策 ] はじめてのスレッド <よりみち1> : 匿名クラスで書く。

シリーズ一覧
[Java Gold対策] はじめてのスレッド 1日目 : スレッドとは?
[Java Gold対策] はじめてのスレッド 2日目 : スレッドの作り方
[Java Gold対策] はじめてのスレッド 3日目 : スレッドの作り方2
[Java Gold対策] はじめてのスレッド <よりみち1> : 匿名クラスで書く。 
[Java Gold対策] はじめてのスレッド <よりみち2> : ラムダ式で書く。
[Java Gold対策] はじめてのスレッド 4日目 : スレッドをsleepさせよう
[Java Gold対策] はじめてのスレッド 5日目 : joinメソッドで順番待ち
[Java Gold対策] はじめてのスレッド 6日目 : runメソッドで条件付き停止

目次

よりみちでやること。

ここまで「はじめてのスレッド」といっしょに来てくださった皆様、お疲れ様でした~
これでスレッドの基本の作り方はバッチリです!

ですが、Java8からはもっと簡単に同じ内容のコードを書けるようになりました。
折角ですので、余裕のある方はラムダ式版もマスターしましょう

この「[ Java Gold 対策 ] はじめてのスレッド<よりみち>」では、2つのテーマに寄り道していきます。

  • 匿名クラスでカンタンなコードにする
  • ラムダ式でもっとカンタンなコードにする

どちらもこれまで扱ってきた「Runnableインターフェイスを実装するスレッドの作り方」のサンプルコードを元にお話しますので、安心してついてきてください。

とりあえずすぐに使えるようになりたい!書き方は後で見る!という方は、<よりみち>は飛ばして大丈夫です

余裕のある方、JavaGoldを頑張る方は、いっしょに匿名クラス・ラムダ式についてマスターしていきましょう~!

Oracle Java Goldを目指している方にとっては、匿名クラスとラムダ式は鬼門かと思います。
SilverからGoldになると、mainメソッドと同じくらい、いやそれよりもっと匿名クラス・ラムダ式を見ることになると思います。
今のうちに、少しずつ匿名クラスとラムダ式の世界を体感しておきましょう

はじめまして、匿名クラス。

匿名クラスとは、その名の通り、名前がないクラスのことです。
名前がないため、クラスの定義とインスタンス化を一回の記述で行います

簡略化した書き方なので、書くのはとっても簡単ですが、その分慣れていないと戸惑ってしまう記述かもしれません。 Oracle Java Goldの試験では、知ってて当然!というふうに使われまくるので、一歩ずつチェックしていきましょう。

使いどころをざっくり

匿名クラスは、主にインターフェースを実装した処理や、抽象クラスを継承した処理をそこだけで使いたいときに、使います。

匿名クラスは、親クラスをnewするときに、続けてメソッドやフィールドの定義を書きます。そうすることで、そこで作ったインスタンスだけに定義が反映されます。
使い所の詳しくは最後にまとめていますので、要チェックです。

具体的に見てみる。

説明を聞くより、コードを見たほうがわかりやすい範囲かと思います。
さっそく、「スレッドをRunnableインターフェイスを実装して作成する場合を例に、実際に見ていきましょう。

変更前:これまでの書き方

前回の「[Java Gold対策] はじめてのスレッド3日目 : スレッドの作り方2」の最後のコードと全く同じものです。
Threadクラスがよくわからない方は、ぜひこのシリーズを見てみてください
シリーズ初回:[Java Gold対策] はじめてのスレッド 1日目 : スレッドとは?

このコード、通常通りRunnableインターフェイスを実装したSampleThread2というクラスを作っています。
これは、匿名ではなく、いうなれば「有名」ですかね。
しっかりと名前をつけて、クラスを定義しています。
そして、別のクラス(SimpleThreadMain2)のmainメソッドから、SampleThread2のインスタンスを生成しています。

// Runnableインターフェイスを実装した「有名」クラス
class SampleThread2 implements Runnable {		
	public void run() {		
		for(int i = 0; i < 10; i++) {
			System.out.println("SampleThread2のrunメソッド(" + i + ")");
		}
	}
}

public class SampleThreadMain2 {
	public static void main(String[] args) {
		SampleThread2 t = new SampleThread2();
		// SimpleThread2オブジェクトを引数にしてThreadオブジェクトを生成
		Thread thread = new Thread(t);
		thread.start();
		
		for (int i = 0; i < 10; i++) {
			System.out.println("SampleThreadMain2のmainメソッド(" + i + ")");
		}
	}
}

実行結果:2つのスレッドが動作することが確認できます。

SampleThread2のrunメソッド(0)
SampleThreadMain2のmainメソッド(0)
SampleThreadMain2のmainメソッド(1)
SampleThread2のrunメソッド(1)
SampleThreadMain2のmainメソッド(2)
// 略 //

変更後:匿名クラスVer.

さて、いよいよ匿名クラスです。
名前をつけずに、実装をそのまま書くとはどういうことなのでしょうか?

今回は、Runnableインターフェイスを実装したオブジェクトを、Threadクラスのコンストラクタに渡したい状況です。
こんなときには、Threadクラスのコンストラクタの引数の中で、直接Runnableインターフェイスに実装させたい処理を書いてしまえばOKです。

public class SampleThreadMain2 {
    public static void main(String[] args) {
    
        // Threadクラスのコンストラクタの引数の中で
	// Runnableインターフェイスの実装を書く
        Thread thread = new Thread(new Runnable() {
            @Override
            public void run() {
                for (int i = 0; i < 10; i++) {
                    System.out.println("SampleThread2のrunメソッド(" + i + ")");
                }
            }
        });
        // ↑ここまでずっと、コンストラクタの引数
        
        thread.start();

        for (int i = 0; i < 10; i++) {
            System.out.println("SampleThreadMain2のmainメソッド(" + i + ")");
        }
    }
}

6行目の「Thread thread = new Thread(」から、13行目にカッコが閉じるまで、これはすべてThreadコンストラクタの引数です。(長いですね!)

さて、6行目に「new Runnable()」という謎の記述がありますね。
「あれ?インターフェイスはインスタンス化できないから、newできないんじゃないの?」と思ったあなた。
とてもいい気付きです!

インターフェイスをnewする、だと!?

一見タブーのようなこの表記ですが実は、匿名クラスとしてその後に「 { } 」で実装の内容を書いているので、可能になります!

なぜインターフェイスはインスタンス化できないのか?
インターフェイスは「型情報を提供するもの」であり、「実際の処理は持たない」からです。
なにをやるか、という情報を持っていないにも関わらず、オブジェクトという実体・モノを生成することは、もちろんできませんよね。

この考え方からいくと、今回はしっかりと「実際の処理」を渡してあげているので、問題なくnewできる、実体化できる、というわけですね。

今の説明を具体的に見ていきましょう。

Runnableインターフェイスにはrunメソッドという抽象クラスが定義されています。
この状態では、runメソッドが実際になにをするのかという「実装」の部分はなにもありません。
したがって、そのままインスタンス化することはできません。

そこで、runメソッドをOverrideした内容をnewと同時に渡してあげることによって、runメソッドは「実装された」ことになります。
その結果、Runnableインターフェイスを実装した名前のないクラスのインスタンスを生成する」と扱うことができ、オブジェクトという実体化することができるのです!

長ったらしく説明しましたが、つまり、
Runnableインターフェイスを実装したクラスを作り、そのインスタンスを生成した
と、同じ処理をしているんですね。

匿名クラスは便利なツール

こうしてみると、この匿名クラスはとっても便利なことがおわかりいただけると思います。

パッと見るだけで、コード量が減っていることがわかりますね。
また、匿名クラスを使うということは、インターフェイスを実装したクラスを「名前をつけてわざわざ定義する」必要がなくなります。
今回のような使い方ならば「その場で一回だけインスタンスが作れれば良い」のです。

そのため、変更前のコードでは別に用意していた「SampleThread2」というクラスが必要なくなりました!
そして、処理はmainメソッドから移動しなくなりました。
すると、処理の流れを一直線でたどることができるため、とっても可読性が上がったこともわかりますね!

匿名クラスの使い所

先ほども述べましたが、「その場で一回だけインスタンスが作れれば良い」というような状況に、匿名クラスはぴったりです。

逆に、後で別の処理にそのインスタンスを使う場合は、匿名クラスは使えません。
なぜなら、インスタンスを変数に入れて保存しておくことができないからです。

インスタンスを変数に入れて保存しておくには、いれるための変数の宣言が必要です。
変数の宣言には、型が必要ですよね!
型はつまりは、クラスの名前でした。

匿名クラスは名前がない
→ 型が指定できない
→ 変数を宣言できない
→ インスタンスを保存できない

ということになります。
なので、例えば「引数として渡すだけ!」のような「その場限り」の場合にしか使えません。

まとめ・次回予告

なんとなく匿名クラスについて理解できたでしょうか?
わかりきれていない部分もあると思いますが、何個も例を見ていくことで自然と入ってくるようになりますよ!

せっかくここまでスッキリさせたコードですので、どうせならもっとスッキリさせましょう!
というわけで、次回はラムダ式についてお話します。

今回よりも、もっと!便利に、シンプルになっていきますよ。
また、ラムダ式は資格試験の鬼門でもありますので、張り切っていきましょう

では次回も、お楽しみに

(Visited 30 times, 1 visits today)
よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

株式会社NEUGATEは、都内で企業研修や職業訓練を運営している会社です。主に、IT系の教育事業に力を入れています。
この記事は、株式会社NEUGATEの教育事業部が執筆をしています。

企業ホームページ:https://neugate.co.jp/

コメント

コメントする

目次