
いまさら聞けない「Javadoc」と「アノテーション」入門
株式会社ガリレオ
小山博史
2011/5/19
よく使う3つの標準アノテーション型
アノテーションをソースコードへ埋め込むためには、コンパイラがチェックできるように、どんなアノテーションを使うのかをアノテーション型として最初に定義しておく必要があります。開発者は定義されているアノテーション型を使って、注釈を付けたいクラス、メソッド、変数などにアノテーションを付けます。
Javaには標準アノテーション型として、java.langパッケージに「Override」「Deprecated」「SuppressWarnings」が定義されています。これらは、よく使いますし、分かりやすいので、具体的にどういった使い方をすればいいのか、確認してみましょう。概要は、次の通りです(下記リストはインデックスになっています)。
- Override
スーパークラスのメソッドをオーバーライドするという注釈 - Deprecated
クラスやメソッドが非推奨であるという注釈 - SuppressWarnings
コンパイル時の警告を抑制するという注釈
■ 【1】Override
Overrideは、スーパークラスのメソッドをオーバーライドするという注釈を付けたいときに使用します。次のクラスをコンパイルしてみましょう。「StandardPrinter」というクラスのtoStringメソッドを呼び出して、「StandardPrinter」という文字列をコンソール画面へ出力するプログラムです。
package sample22.app2;
public class StandardPrinter {
public String toStrimg() {
return "StandardPrinter";
}
public static void main(String[] args) {
StandardPrinter app = new StandardPrinter();
System.out.println(app.toString());
}
}
実行結果(例)
sample22.app2.StandardPrinter@ca0b6
このプログラム作成者は、「app.toString()」を使って「StandardPrinter」という文字列を表示したかったのですが、表示されません。なぜでしょうか。注意深い読者の皆さんは、すでにお気付きでしょう。
StandardPrinterクラスのtoString()メソッドは、StandardPrinterクラスのスーパークラスであるObjectクラスのtoString()メソッドをオーバーライドしたつもりがタイピングミスにより、toStrimg()メソッドとなっています。toString()メソッドをオーバーライドするという情報はコードに含まれていませんから、コンパイラはコンパイルエラーを出しません。toStrimg()メソッドというtoString()メソッドとは別のメソッドが宣言されたものだとして扱います。
慎重深い読者からすると、「こういったタイプミスは普通しないだろう」と思うでしょうが、実際の開発現場ではありがちなミスで、しかも記述した本人もタイプミスをしたとは思っていないものですから、なかなかこの間違いに気付けず、「なぜ、toString()メソッドのオーバーライドがされないのか?」と全然別のことを考えながら、バグがどこにあるか探すことになります。散々調査をした揚げ句、ようやくタイピングミスだということに気付き、脱力感を感じることになります。
こういった単純ミスを防ぐために、Overrideアノテーション型のアノーテションを利用します。具体的には「@Override」をメソッドの修飾子へ付けます。これにより、開発者はコンパイラへ、このメソッドはスーパークラスのメソッドをオーバーライドすることを知らせます。
次のように、StandardPrinterクラスをコピーして、StandardPrinter1クラスを作ってから、toStrimg()メソッドへ@Overrideと付けてみましょう。すると、コンパイルエラーとなります。Eclipseではエディタ上でtoStrimgの行に赤下線が表示されるので、開発者はすぐにエラーメッセージを確認してタイプミスに気付くことができます。
package sample22.app2;
public class StandardPrinter1 {
@Override
public String toStrimg() {
return "StandardPrinter";
}
public static void main(String[] args) {
StandardPrinter1 app = new StandardPrinter1();
System.out.println(app.toString());
}
}
StandardPrinter1クラスを次のように修正しましょう。すると、コンパイルエラーは出なくなり、開発者の意図通り、StandardPrinter1でObjectクラスのtoString()メソッドをオーバーライドできたことになります。
package sample22.app2;
public class StandardPrinter1 {
@Override
public String toString() {
return "StandardPrinter";
}
public static void main(String[] args) {
StandardPrinter1 app = new StandardPrinter1();
System.out.println(app.toString());
}
}
実行結果(例)
StandardPrinter
■ 【2】Deprecated
Deprecatedは、クラスやメソッドが非推奨であるという注釈を付けてたいときに使用します。例えば、次のような「User」クラスと「App」クラスがあったとします。
sample22.app3.Userクラスpackage sample22.app3;
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String get_name() { return name; }
}
sample22.app3.Appクラス
package sample22.app3;
public class App {
public static void main(String[] args) {
User user = new User("koyama");
System.out.println(user.get_name());
}
}
最初のバージョンではUesrクラスのnameを取得するためのメソッドとしてget_name()メソッドを用意しましたが、バージョンアップ時に、このメソッド名をgetName()メソッドという名前に変更することになったとします。ただし、既存のプログラムとの互換性は維持し、新しく作成するプログラムでは新しい名前しか使わないようにしたいとします。
そんなときは、次のようにプログラムを変更することになるでしょう。ここでは、サンプルなのでパッケージを変更しています。
sample22.app4.Userクラスpackage sample22.app4;
public class User {
private String name;
public User(String name) {
this.name = name;
}
@Deprecated
public String get_name() { return getName(); }
public String getName() { return name; }
}
sample22.app4.Appクラス
package sample22.app4;
public class App {
public static void main(String[] args) {
User user = new User("koyama");
System.out.println(user.get_name());
System.out.println(user.getName());
}
}
これで互換性を維持することはできますが、新しく作成するプログラムでgetName()メソッドを使うようにするには、開発者がそのことに簡単に気が付くようにする必要があります。そのために、Userクラスでは、get_name()メソッドへアノテーション「@Deprecated」を指定しています。こうすると、get_name()メソッドを使っているクラスでは、警告が表示されるようになります。
Eclipse上ではget_name()メソッドに取り消し線が付きますし、これを使用するクラスでは警告が表示されます。
■ 【3】SuppressWarnings
少し古いライブラリを使っていると、ジェネリックスを使っていないために、型について安全なプログラミングができない場合があります。そんなときは、キャストを行いますが、コンパイル時に警告が出てしまいます。意味を理解して対処している場合は、この警告を抑制して表示されないようにしたいときがあります。
こういったときは、SuppressWarningsアノテーション型を使うと、コンパイラはコンパイル時の警告を抑制します。これは警告を抑制するために用意されているアノテーション型ですから、適切に使用しないと、本来修正が必要であるコードへの警告まで抑制してしまうことがあるので、適用範囲に気を付けましょう。つまり、むやみにclass全体へ適用しないようにしてください。
ジェネリックスを使っていないsample22.app5.libパッケージがあったとして、この中にUserクラス、UserManagerクラスがあるとします。
sample22.app5.lib.UserManagerクラスpackage sample22.app5.lib;
import java.util.ArrayList;
import java.util.List;
public class UserManager {
private List list = new ArrayList();
public List getList() { return list; }
public void add(Object user) { list.add(user); }
public Object get(int index) { return list.get(index); }
public void remove(int index) { list.remove(index); }
}
sample22.app5.lib.Userクラス
package sample22.app5.lib;
public class User {
private String name;
public User(String name) {
this.name = name;
}
public String getName() { return name; }
}
このライブラリを使うsample22.app5.Appクラスを次のように作成したとします。すると、「List<User> list = (List<User>)um.getList();」でコンパイラが警告を出します。ここでは、UserManagerクラスでは、必ずUserクラスしか登録しないため、UserManagerクラスのgetListメソッドを呼び出すと、「List<User>」となっていることが分かっています。こういった場合は、コンパイラが出す警告の表示を抑制したくなります。
sample22.app5.Appクラスpackage sample22.app5;
import java.util.List;
import sample22.app5.lib.User;
import sample22.app5.lib.UserManager;
public class App {
private UserManager um = new UserManager();
public void exec() {
User user = new User("koyama");
um.add(user);
List<User> list = (List<User>)um.getList();
User u = list.get(0);
System.out.println(u);
}
public static void main(String[] args) {
App app = new App();
app.exec();
}
}
sample22.app6.Appクラスを次のように作成して、次のようにSuppressWarningsアノテーションを指定します。
Eclipseでは「(List<User>)um.getList()」にマウスカーソルを近づけると、「@SuppressWarnings 'unchecked'を'exec()'に追加します」と修正案を表示しますが、ここではローカル変数「list」に対して指定します。「@SuppressWarnings 'unchecked'を追加すればいい」ということがEclipseのメッセージから分かるので、「@SuppressWarnings("unchecked")」と書きます。すると、警告の出力が抑制されます。
package sample22.app6;
import java.util.List;
import sample22.app5.lib.User;
import sample22.app5.lib.UserManager;
public class App {
private UserManager um = new UserManager();
public void exec() {
User user = new User("koyama");
um.add(user);
@SuppressWarnings("unchecked")
List<User> list = (List<User>)um.getList();
User u = list.get(0);
System.out.println(u);
}
public static void main(String[] args) {
App app = new App();
app.exec();
}
}
さて、Override、Deprecated、SuppressWarningsといったアノテーション型について説明をしました。これらを利用する分には、以上の知識で何となく使えてしまいますから、それほど難しくはないでしょう。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 -
