
継承やオーバーライドで簡単にクラスを“拡張”しよう
株式会社ガリレオ
小山博史
2009/11/13
自作クラスを継承・拡張してみよう
クラスの拡張をするに当たっては、メンバー(フィールドとメソッド)の実装継承と、実装の再定義(オーバーライド)について理解をする必要があります。
■ 「スーパークラス」と「サブクラス」、そして「継承」とは
次の例では、クラスBaseを拡張して、クラスAを作成しています。クラスBaseのことを、クラスAの「スーパークラス」「親クラス」と呼びます。また、クラスAのことを、クラスBaseの「サブクラス」「子クラス」と呼びます。このように、クラス名の後に、extendsを書いて、そのクラスのスーパークラスとなるクラス名を記述することにより、クラスの拡張ができます。
クラス拡張の宣言方法class A extends Base {
// 拡張のためのコード
}
クラスを拡張することにより、クラスAはクラスBaseが公開しているフィールドやメソッドを実装していることになります。このことを、「クラスAはクラスBaseのフィールドとメソッドを継承(inherit)している」と表現します。このため、「Aには追加したいフィールドやメソッドについてのみコーディングをすればいい」ということになります。
また、サブクラスはスーパークラスがサブクラスへアクセスを許しているフィールドやメソッドを利用できます。例えば、BaseクラスがbaseFieldフィールドを持ち、baseMethodメソッドを実装して、両方ともサブクラスが使えるように宣言していたとすると、AクラスはbaseFieldフィールドへアクセスできますし、baseMethodメソッドを呼び出すこともできます。この辺りの話は次回以降の記事で取り上げます。ここでは、そういうものがあるという程度の理解で結構です。
コラム 「次回で詳しく解説する“アクセス制限”とは」 |
| アクセス制限については、これまで説明をしていませんが、次回以降の記事で予定しています。詳細はそのときに説明しますので、ここでは簡単な説明だけをしておきます。 これまで「public」というキーワードがついているメソッドやフィールドがあったと思いますが、これは、どのクラスにも公開されていることを意味します。「private」というキーワードがついているメソッドやフィールドは、そのクラスでしか使えません。「protected」というキーワードがついているメソッドやフィールドは、そのクラスのサブクラスがアクセスできます。public、private、protectedが付いていないメソッドやフィールドについては、同一パッケージ内のクラスからアクセスができます。この4点が基本です。 |
■ 自作クラスを拡張するには
例として、sample12.Baseクラスを用意し、これをスーパークラスとして利用するsample12.Aクラスを用意してみましょう。文法を理解するためのものなので、実用性はまったくありませんが、ここまでの説明を理解する役には立ちます。単純にbaseFieldフィールドを宣言して1で初期化し、baseMethodメソッドは常にfalseを返すよう実装しています。
sample12/Base.javapackage sample12;
class Base {
int baseField = 1;
boolean baseMethod() {
return false;
}
}
sample12.Aクラスはsample12.Baseクラスを拡張して、aFieldフィールドとaMethodメソッドを追加しています。このメソッドでは、スーパークラスであるsample12.BaseクラスからbaseFieldフィールドとbaseMethodメソッドを継承しているため、ほかのクラスから使えるようになっています。sample12.Aクラスの中にあるメソッドでもbaseFieldフィールドとbaseMethodメソッドは利用できるので、aMethodメソッド内で使っています。
sample12/A.javapackage sample12;
class A extends Base {
int aField = 10;
boolean aMethod() {
//スーパークラスのフィールドとメソッドを利用
System.out.println("aMethod:baseField:" + baseField);
return !baseMethod();
}
}
処理内容は単純ですが、念のため確認をしておきます。「"aMethod:baseField:" + baseField」を出力して、「!baseMethod()」の計算結果を返すという処理です。baseMethod()は、sample12.Baseクラスから継承したメソッドなので、必ず「false」となりますから、「!baseMethod()」は常に「true」となります。
注釈 「『論理否定』って何か分かってる?」 |
| 本連載ではこれまで出てきませんでしたが、「!」は「論理否定」の単項演算子で、後に続く値を否定します。つまり、「!false」は「true(falseではない)」となり、「!true」は「false(trueではない)」となります。 |
最後に、これらを利用するsample12.Sample02クラスを作成します。起動メソッド(mainメソッド)を持ち、その中でsample12.Baseクラス、sample12.Aクラスのインスタンスを生成し、それぞれが持つフィールドにアクセスをしたり、メソッドを呼び出したりしています。
sample12/Sample02.javapackage sample12;
public class Sample02 {
public static void main(String[] args) {
Base base = new Base();
A a = new A();
// Baseクラスのフィールドとメソッド
System.out.println("base.baseField :" + base.baseField);
System.out.println("base.baseMethod():" + base.baseMethod());
// AクラスはBaseクラスと同じフィールドとメソッドを持つ
System.out.println("a.baseField :" + a.baseField);
System.out.println("a.baseMethod() :" + a.baseMethod());
// Aクラス独自フィールドへのアクセス
System.out.println("a.aField :" + a.aField);
// Aクラス独自メソッドの呼び出し
System.out.println("a.aMethod() :" + a.aMethod());
// baseとaは別インスタンスなので、
// base.baseFieldとa.baseFieldの値は別になる
base.baseField = 3;
System.out.println("base.baseField :" + base.baseField);
System.out.println("a.baseField :" + a.baseField);
a.baseField = 30;
System.out.println("base.baseField :" + base.baseField);
System.out.println("a.baseField :" + a.baseField);
}
}
実行結果は、次のようになります。
sample12.Sample02クラスの実行結果base.baseField :1
base.baseMethod():false
a.baseField :1
a.baseMethod() :false
a.aField :10
aMethod:baseField:1
a.aMethod() :true
base.baseField :3
a.baseField :1
base.baseField :3
a.baseField :30
sample12.AクラスにはbaseFieldフィールドやbaseMethodメソッドの宣言はありませんが、きちんと使えていて、Baseクラスのものと同じ結果になっていることが分かります。sample12.Aクラス独自のフィールドへはアクセスできて「a.aField :10」という結果が出ています。aMethodメソッドの呼び出しにより、「aMethod:baseField:1」が出力されてから、「a.aMethod() :true」という正しい結果も出力されています。
baseとaは別インスタンスなので、base.baseFieldとa.baseFieldの値は別になっています。base.baseFieldが3になってもa.baseFieldの値は1のままですし、a.baseFieldの値を30にしても、base.baseFieldには影響がありません。
■ クラスを拡張する際の5つの注意点
どうでしょうか、クラスの拡張をすることにより、サブクラスはスーパークラスのフィールドやメソッドをあらためてコーディングしなくてもいいことが理解できたでしょうか。さて、クラスを拡張するに当たっては、次の項目について検討が必要です。1.と2.については、実装の仕方はいま確認をしたところなので、いいでしょう。ここからは、残りの項目について順番に見ていくことにします。
- どういったフィールドを追加するか
- どういったメソッドを追加するか
- クラスの振る舞いを変えるか
- どういったコンストラクタを用意するか
- 同値性についてどうするか
コラム 「実は、あなたも継承しているObjectクラス」 |
| すべてのクラスは、Objectクラスを拡張していることを最初に書きました。これはJava APIドキュメントを見ると分かりますが、どのクラスもスーパークラスをたどっていくと、Objectクラスにたどり着くのです。実は、Javaでは、クラス宣言時にextendsを使ってスーパークラスを指定しない場合は、暗黙のうちにObjectクラスを拡張します。ですから、equalsメソッドやhashCodeメソッドなどはメソッドを実装しなくても使えるようになっています。試しに、sample12.Baseクラスでこれらのメソッドが使えるかサンプルコードを書いて実行してみるといいでしょう。次のように書くことができ、コンパイルエラーは出ません。実行もできます。 ソースコード例 |
オーバーライドでクラスの振る舞いを変える
もし、クラスの振る舞いを変えたいのであれば、スーパークラスのメソッドを「オーバーライド(override、無視する)」するために、同名のメソッドを宣言し、あらためて実装します。単に拡張しただけでも、メソッドは“継承”のみされるのですが、このように明示的に実装をすることによって、プログラムの動作を変更できるのです。
■ オーバーライドにはアノテーションが必要?
オーバーライドをする場合は、アノテーションの「@Override」を書いて、次の行にオーバーライドしたいメソッドの宣言と新しい処理を記述します。実は、アノテーションについては書かなくてもコンパイラではエラーが出ません。しかし、単純ミスを防ぐためにはこれを記述する癖を付けておいた方がいいですし、後ほど説明するEclipseの機能でメソッドのオーバーライドをすると、これが自動で付きますから覚えておくようにしてください。アノテーションについては、後の連載で別途説明しますので、ここでは単純に「@Override」と書いておけばいいと覚えれば十分です。
@Override
戻り型 メソッド名(仮パラメータ型 仮パラメータ名) {
新しい処理
}
■ Eclipseでクラスを拡張する
それでは、sample12.Aクラスを拡張するsample12.Bクラスを用意し、aMethodメソッドのオーバーライドをしてみましょう。全部自分で記述してもいいですが、Eclipseにはメソッドのオーバーライドを簡単にするための機能が付いているので、それを使ってみましょう。
- パッケージエクスプローラでsample12パッケージをマウスの右ボタンでクリック
- 表示されるメニューで[新規]→[クラス]を指定
- [新規Javaクラス]の画面で[名前]に「sample12.B」を指定
- [新規Javaクラス]の画面で[スーパークラス]に「sample12.A」を指定して[完了]をクリック
- パッケージエクスプローラでsample12パッケージのB.javaをマウスの右ボタンでクリック
- 表示されるメニューで[ソース]→[メソッドのオーバーライド/実装(V)...]を指定
- AクラスのaMethodにチェック(図5)
- [OK]をクリック
![]() |
| 図5 オーバーライドするメソッドの指定 |
次ページでは、さらにオーバーライドについて説明し、キーワード「super」でスーパークラスへアクセスする方法にも触れます。
| 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 -

