
あなたの知らない、4つのマニアックなJava文法
株式会社ガリレオ
小山博史
2010/7/27
【3】無名内部クラス(匿名クラス)
内部クラスには、「無名内部クラス」と呼ばれるものもあり、「無名クラス」と呼ばれることもあります。実はJavaでは、クラスに名前を付けずに利用することもできます。その方法で宣言された内部クラスは名前を持たないので、「無名内部クラス」といわれます。RemainViewクラスは、無名内部クラスで実装できます。
Eclipse上でsample17.App4クラスをコピーしてsample17.App7クラスを作成します。sample17.App4クラスのメンバからRemainViewクラスを削除してから、コンストラクタ内で無名内部クラスで登録するようにします。次のように変更します。実行結果はsample17.App4Runクラスの結果と同様なので、省略します。
sample17/App7.javaに作った無名内部クラス// 略
view.addObserver(resultView);
// 無名内部クラス
view.addObserver(new Observer() {
@Override
public void update() {
System.out.println("残り時間:" + count + "[sec]");
}
});
// 略
■ 無名内部クラスは制限が多い
このように、無名内部クラスはクラス名を指定せずに実装したいインターフェイスやクラスをnewしながら、そこに実装が必要なコードを記述します。無名内部クラスは、明示的なコンストラクタを持てませんし、これを継承するクラスを作成できません。明示的なextends節やimplements節を持つこともできません。ほかにもありますが、こういったいくつかの制限があります。
明示的なコンストラクタを持てないので、インスタンス生成時の初期化については、それほど自由度はありません。とはいえ、初期化子と初期化ブロックを持つことはできます。
■ 無名内部クラスの継承はextendsを使わない
また、コンストラクタを持つクラスをextendsした無名内部クラスを指定する場合は、スーパークラスのコンストラクタを呼び出しているかのように指定しつつ、オーバーライドしたいメソッドも実装できます。次のようなsample17.App8クラスを作成してみましょう。
sample17/App8.javapackage sample17;
public class App8 {
class Ic implements Ii {
String value;
Ic(String v) {
value = v;
}
public void print() {
System.out.println("Ic1:" + value);
}
}
interface Ii {
void print();
}
Ii[] objs = new Ii[5];
public void execute() {
objs[0] = new Ic("objs[0]");
objs[1] = new Ic("objs[1]") {
public void print() {
System.out.println("無名内部クラス objs[1]:" + value);
}
};
objs[2] = new Ii() {
public void print() {
System.out.println("無名内部クラス objs[2]:");
}
};
objs[3] = new Ii() {
String value = "objs3";
public void print() {
System.out.println("無名内部クラス objs[3]:" + value);
}
};
objs[4] = new Ii() {
String value;
{
value = "objs" + 4;
}
public void print() {
System.out.println("無名内部クラス objs[4]:" + value);
}
};
for (Ii o : objs) {
o.print();
}
}
public static void main(String[] args) {
App8 app8 = new App8();
app8.execute();
}
}
このクラスでは、ネストしたインターフェイスとしてprintメソッドだけを宣言したIiインターフェイスと、それを実装した内部クラスIiを宣言しています。フィールドとしては、Ii型の配列であるobjsだけを持ちます。
objsの最初の要素には、Icクラスをインスタンス化して代入しています。添え字1の要素には、Icクラスをextendsした無名内部クラスのインスタンス化をして代入しています。IcクラスのコンストラクタはString型のパラメータを受け取るので、それを指定しつつ、printメソッドをオーバーライドしています。
添え字2以降の要素へは、Iiインターフェイスをimplementsした無名内部クラスをインスタンス化して代入しています。初期化子や初期化ブロックを使って初期化しています。
最後に、動作確認のために「拡張for文」を使って配列の各要素のprintメソッドを実行しています。以下は、実行結果です。
App8.javaの実行結果Ic1:objs[0]
無名内部クラス objs[1]:objs[1]
無名内部クラス objs[2]:
無名内部クラス objs[3]:objs3
無名内部クラス objs[4]:objs4
■ 使いどころ
複雑なデータ構造を内部に持ったり、たくさんのメソッドを持つようなクラスの場合は、無名内部クラスで実装すると可読性が落ちますし、メンテナンスもしにくいので、普通は採用しません。
また、継承によって実装を再利用できませんから、コードを再利用したい場合に採用できません。しかし、RemainViewクラスのように、コンストラクタの必要がなく、処理も単純で、別途再利用する予定もないクラスについては、無名内部クラスで実装したくなります。そういった場合に利用するといいでしょう。
使いどころとしては、ほかにも以下のような例があります。
【4】ローカル内部クラス
無名内部クラスとして実装するには複雑なクラスではあるものの、sample17.App4のコンストラクタ内で1度だけ定義すれば十分なクラスがあったとします。そんな場合は、「ローカル内部クラス」を使います。ローカル内部クラスは、コンストラクタに限らず、メソッド内で宣言できます。
RemainViewクラスをローカル内部クラスを使って実装することもできます。sample17.App7クラスをコピーをしてsample17.App9クラスを作成します。sample17.App9クラスのコンストラクタ内で、次のようにRemainViewクラスを宣言します。
sample17/App9.javaのコンストラクタ
// 略
App9() {
count = 12;
resultView.setStartValue(count);
view.addObserver(progressView);
view.addObserver(resultView);
class RemainView implements Observer {
@Override
public void update() {
System.out.println("残り時間:" + count + "[sec]");
}
}
view.addObserver(new RemainView());
}
// 略
RemainViewクラスは無名内部クラスで実装しても構わないクラスでしたから、このようにローカル内部クラスで実装する利点が見当たらないので、ピンと来ないかもしれません。ローカル内部クラスとすることで、「どこからどこまでがひとまとまりなのか明確になる」という点だけ理解しておいてください。
■ 使いどころ
GUIアプリケーションなどでは、そこそこ複雑な初期化や処理を持つものの、コンストラクタ内でしか必要のないクラスが出てくる場面がよくあります。
そういったクラスを無名内部クラスで実装すると、どこからどこまでがクラスの宣言なのかよく分からなくなってしまいます。そういったときに、ローカル内部クラスはよく使われます。
LLほどではないが、Javaでも軽量に
前回、今回と、たくさん細かい話が出ましたが、ネストしたクラスについて理解できたでしょうか。初心者のうちは、「自分でネストした型を宣言して使う」機会は、それほど多くはないかもしれませんが、ほかの開発者のコードで見かけることはあるかと思います。そういったときのために、細かい点についても説明をしました。
筆者の考えでは、初心者がネストした型を使う場面は、「同一ファイル内で必要になった時点でクラスを、その場で作成して、いろいろ試してみる」といったライトウェイトプログラミングをするときぐらいです。
Javaでは、RubyやPythonといったLL(Lightweight Language、軽量プログラミング言語)ほど軽量なプログラミングはできませんが、前回と今回で紹介をしたネストした型や内部クラスをうまく利用することで、「思い付いたままに試行錯誤しながらプログラミングをする」といったことが手軽にできるようになります。
試しに作ってみるようなプログラムでは、どんどん使って素早くやりたいことを実現してみましょう。もちろん、通常の開発でもネストした型は有用な場面はありますから、適材適所で利用できるようになりましょう。今回作ったサンプルのソースコードはこちらからダウンロードできます。
■ @IT関連記事
| 標準化進む新スクリプト言語“Groovy” J2EE Watch (3) JSR-241として、Javaの標準仕様に組み込まれようとしているスクリプト言語“Groovy”。Javaの一部になろうとしているこの言語の正体とは? 「Java Solution」フォーラム 2004/8/19 |
| コンポーネント化でクラスをすっきり整理 保守性・拡張性に優れたシステムを作る(5) コンポーネント化は、システムの拡張性・保守性を検討するうえで必須の要素である。まずはコンポーネントの基礎から |
| 部分クラスと静的クラス 連載:C# 2.0入門 (6) クラス定義を便利で多彩にする2つの機能について解説。C# 2.0でクラスをメソッドやデータの入れ物として活用する場合にはこれらは大いに役立つ 「Insider.NET」フォーラム 2007/10/30
|
| Java SE コアAPI 使用コード例一覧 Java開発者/プログラマのための、Java SEコアAPIの使用コード例の記事へのJavadocっぽいリンク集。メソッドやコンストラクタ、例外などAPIの使い方の参考にしてください 「Java Solution」フォーラム 2009/3/24 |
| 筆者プロフィール |
| 小山博史(こやま ひろし) 情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)やbugs(J)の活動へも参加している。 著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。 |
| Index | ||||||||
|
||||||||
【改訂版】Eclipseではじめるプログラミング バックナンバー 連載インデックスへ»
- 第1回 Eclipse 3.4で超簡単Javaプログラミング基礎入門
- 第2回 Javaで一から理解するプログラムの変数と演算子
- 第3回 プログラミングの醍醐味! Javaで“条件式”を理解する
- 第4回 プログラミングの真骨頂! Javaで“反復処理”を覚える
- 第5回 データ集合を扱うのに便利なJavaの配列と拡張for文
- 第6回 複雑なデータを表現できるクラスやフィールドって?
- 第7回 クラスの振る舞いを表すJavaの“メソッド”とは?
- 第8回 Javaの参照型を文字列操作で理解して文法を総復習
- 第9回 プログラムを「変更」しやすくする“インターフェイス”
- 第10回 Javaの実案件に必須のパッケージとインポートを知る
- 第11回 「static」でクラス共有の変数・メソッドを使いこなせ!
- 第12回 継承やオーバーライドで簡単にクラスを“拡張”しよう
- 第13回 “コンストラクタ”と初期化、本当に理解できてる?
- 第14回 再利用性の高いクラス作成に重要な“アクセス制御”
- 第15回 Javaは「抽象クラス」で実装を上手に再利用できる
- 第16回 “ネスト”した型で始める軽量Javaプログラミング!?
- 第17回 あなたの知らない、4つのマニアックなJava文法
- 第18回 強く型付けされているJavaの理解に必修の“型変換”
- 第19回 キュー構造をJavaで実装してジェネリック型を理解する
- 第20回 拡張for文の真の実力を知り、反復処理を使いこなせ
- 第21回 7ステップで理解するJavaでの列挙型/enum使用法
- 第22回 いまさら聞けない「Javadoc」と「アノテーション」入門
- 第23回 プログラマの宿命! 例外とエラー処理を理解する
- 第24回 Javaの例外処理で知らないと損する7つのテクニック
| Java Solution全記事一覧 |
TechTargetジャパン
- Scalaのパッケージ、アクセス修飾子、オブジェクト継承 (2012/5/22)
インポート、パッケージオブジェクト、抽象クラス/抽象メソッド、オーバーライド、final、シールドクラスなども - 基幹系システムでCloud SQLは使えるか試してみた (2012/5/17)
サンプルとしてMRPシステムを作成して動かし、「再帰呼び出し」などのパフォーマンスを測定して検証してみます - アジャイル管理ツール9選+Pivotal Tracker入門 (2012/5/14)
群雄割拠のアジャイルプロジェクト管理ツールを9つ紹介し、特に注目を集めているPivotal Trackerの基本的な使い方を解説します - サーバサイドJSやJavaでWebアプリが作れるXPages (2012/5/11)
Notes/Dominoの資産をサーバサイドJavaScriptやJavaで操作し、HTMLやJavaScript、CSSをUIにできる技術を紹介
|
|
キャリアアップ
スポンサーからのお知らせ
- - PR -
イベントカレンダー
- - PR -

