プログラムを「変更」しやすくする“インターフェイス”:【改訂版】Eclipseではじめるプログラミング(9)(3/3 ページ)
これからプログラミングを学習したい方、Javaは難しそうでとっつきづらいという方のためのJavaプログラミング超入門連載です。最新のEclipse 3.4とJava 6を使い大幅に情報量を増やした、連載「Eclipseではじめるプログラミング」の改訂版となります
Eclipseでインターフェイスを実装したクラスを作るには
次に、このDiceIFを実装するクラスとして「いかさまダイスのFakeDice」と「本物ダイスのRealDice」を作成します。まず、次のようにFakeDiceクラスを作成します。
- [パッケージ・エクスプローラー]の[Sample]をマウス右ボタンでクリック
- 表示されるポップアップメニューで[新規]→[クラス]を指定
- 表示される[新規Javaクラス]ダイアログで、[名前]に「FakeDice」と入力
- [追加]ボタンをクリック
- 表示される[インプリメントされたインターフェイスの選択]ダイアログで[インターフェイスを選択してください]の欄に「DiceIF」と入力(図3)
- [OK]ボタンをクリック
- [新規Javaクラス]ダイアログで、[インターフェイス]にDiceIFが追加されたことと、[どのメソッド・スタブを作成しますか?]のところにある[public static void main(String[] args)]のチェックが付いていないことを確認(図4)
- [終了]ボタンをクリック
図4 [新規Javaクラス]ダイアログで、[インターフェイス]にDiceIFが追加されたことと、[どのメソッド・スタブを作成しますか?]のところにある[public static void main(String[] args)]のチェックが付いていないことを確認
同様にしてRealDiceクラスを作成します。生成されたFakeDiceクラスとRealDiceクラスへフィールドを追加し、「public int roll() { }」内の処理を変更します。具体的には、次のように修正します。
public class FakeDice implements DiceIF { int[] values = new int[] { 3, 4, 2, 1, 5, 6 }; int current = 0; @Override public int roll() { current++; if (current == 6) current = 0; return values[current]; } }
public class RealDice implements DiceIF { java.util.Random r = new java.util.Random(); int maxNum = 6; @Override public int roll() { return r.nextInt(maxNum) + 1; } }
コラム 「アノテーションについて簡単に触れておく」
生成されたコードに「@Override」という行がありますが、これはアノテーションです。アノテーションの詳細は、後ほど別途解説をする予定ですが、簡単に説明をしておきます。
このアノテーションは、「インターフェイスで宣言されているメソッドを実装している」という注釈をプログラムに付けています。ここでは、DiceIFインターフェイスのroll()メソッドを実装しているという印を付けているのです。この注釈はプログラムの実行には影響がありません。
なお、ほかのコードの内容についての解説は連載第7回のものと同じなので、そちらを参照してください。
インターフェイスを実装したクラスを使ってみる
最後に、これらを使用するサンプルクラスSample92を作成します。
- [パッケージ・エクスプローラー]の[Sample]をマウス右ボタンでクリック
- 表示されるポップアップメニューで[新規]→[クラス]を指定
- 表示される[新規Javaクラス]ダイアログで、[名前]に「Sample92」と入力
- 同じ[新規Javaクラス]ダイアログで、[どのメソッド・スタブを作成しますか?]のところにある[public static void main(String[] args)]をチェックする
- [終了]ボタンをクリック
java.util.Listを使ったときと同様にして、DiceIFインターフェイスをパラメータとして持つメソッドrollsを用意して実行します。rollsメソッドでは単純に6回ダイスを振って、その結果を出力するという処理となっています。FakeDiceを使いたいときには、rollsへFakeDiceオブジェクトを渡しますし、RealDiceを使いたいときには、rollsへRealDiceオブジェクトを渡しています。
public class Sample92 { public static void main(String[] args) { Sample92 app = new Sample92(); System.out.println("FakeDice"); app.rolls(new FakeDice()); System.out.println("RealDice"); app.rolls(new RealDice()); } public void rolls(DiceIF dice) { for (int i=0 ; i<6 ; i++) { System.out.println(dice.roll()); } } }
実行結果は下記のようになります。FakeDiceの結果は何度実行しても変わりませんが、RealDiceの結果は実行するたびに変わっているはずです。
Sample92.javaの実行結果
FakeDice 4 2 1 5 6 3 RealDice 6 5 2 3 1
いかがでしょうか。java.util.Listを使ったプログラムと同じようなプログラムを自作できました。このようにインターフェイスを使えば、Diceクラスのコードをいちいち書き換えなくても、FakeDiceとRealDiceを簡単に切り替えができることも理解できたと思います。
コラム 「“インターフェイス継承”と“実装継承”」
FakeDiceクラスもRealDiceクラスも、DiceIFインターフェイスをimplementsすることで、「int roll()というメソッドを持ち、メソッドの処理コードを記述している」ことが分かるようになっていました。このとき、「int roll()というメソッドを持つ」という点に着目した場合は、これらは「インターフェイス継承の関係にある」といいます。
つまり「FakeDiceもRealDiceもDiceIFのインターフェイス継承をしている」ということになります。Javaのimplementsでは、「インターフェイス継承と、インターフェイスの実装(メソッドの処理コード記述)をしている」という両方の意味を含んでいます。
似たような機能として、「実装継承」というものもあります。こちらは、インターフェイスの継承だけでなくインターフェイスを構成するメソッドの処理コード自体も継承します。これは、既存のクラスを機能拡張したい場合によく使います。例えば、java.util.ArrayListクラスを機能拡張して「getメソッドの処理が何回呼ばれたか」というメソッドを1つだけ追加したいというようなときに便利です。
こんなときにJavaでは、java.util.ArrayListと同じようなクラスを自作する必要はなく、「キーワード「extends」を使って、java.util.ArrayListが実装しているコードをそのまま継承して、差分だけコーディングする」という方法が取れます。ちなみに、Javaのextendsは、インターフェイス継承と実装継承のどちらも可能であるため、単に「継承」と訳されます。
「変更」に強いプログラムを作るために
今回は、インターフェイスについて解説をしました。2つのインターフェイスのサンプルプログラムを通して、インターフェイスの便利さを理解してもらえたでしょうか。インターフェイスは重要な概念ですが奥が深いので、すぐにすべてを理解することは難しいと思います。
まずは、JavaのAPIで用意されているクラスについて、インターフェイスを実装している場合は、ほかの似たようなクラスと簡単に切り替えができるようにインターフェイスを使えるようになってください。インターフェイスを使ったプログラミングの経験を積むと、自然と自作インターフェイスの設計ができるようになるはずです。インターフェイスを有効に活用できるようになると、「変更」に強いプログラミングができるようになります。ぜひ、積極的に使うようにしましょう。
インターフェイスを使ったプログラミングができるようになると、同じ名前のクラスを作りたくなることが多くなります。例えば、本当はDiceという名前のインターフェイスを今回作りたかったのですが、DiceIFという名前で作成しました。第7回のときにすでにDiceクラスというものを作成してしまっていたため、同じ名前となるDiceインターフェイスを作成できなかったからです。
こういった問題を解決するために、Javaには「パッケージ」という概念が導入されています。次回はこのパッケージについて解説する予定ですので、お楽しみに。
今回作ったサンプルのソースコードはこちらからダウンロードできます。
筆者紹介
小山博史(こやま ひろし)
情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)やbugs(J)の活動へも参加している。
著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。
- Javaの例外処理で知らないと損する7つのテクニック
- プログラマの宿命! 例外とエラー処理を理解する
- いまさら聞けない「Javadoc」と「アノテーション」入門
- 7ステップで理解するJavaでの列挙型/enum使用法
- 拡張for文の真の実力を知り、反復処理を使いこなせ
- キュー構造をJavaで実装してジェネリック型を理解する
- 強く型付けされているJavaの理解に必修の“型変換”
- あなたの知らない、4つのマニアックなJava文法
- “ネスト”した型で始める軽量Javaプログラミング!?
- Javaは「抽象クラス」で実装を上手に再利用できる
- 再利用性の高いクラス作成に重要な“アクセス制御”
- “コンストラクタ”と初期化、本当に理解できてる?
- 継承やオーバーライドで簡単にクラスを“拡張”しよう
- 「static」でクラス共有の変数・メソッドを使いこなせ!
- Javaの実案件に必須のパッケージとインポートを知る
- プログラムを「変更」しやすくする“インターフェイス”
- Javaの参照型を文字列操作で理解して文法を総復習
- クラスの振る舞いを表すJavaの“メソッド”とは?
- 複雑なデータを表現できるクラスやフィールドって?
- データ集合を扱うのに便利なJavaの配列と拡張for文
- プログラミングの真骨頂! Javaで“反復処理”を覚える
- プログラミングの醍醐味! Javaで“条件式”を理解する
- Javaで一から理解するプログラムの変数と演算子
- Eclipse 3.4で超簡単Javaプログラミング基礎入門
Copyright © ITmedia, Inc. All Rights Reserved.