第4回 クラスの継承の本質を知る
中野克平
2003/3/8
|
今回の内容
|
前回「クラスを簡単に理解する」まで、プリミティブ型とクラス型について説明してきました。コンピュータの中には結局のところCPUとメモリしかありません。「変数は箱だ」といった例え話よりも、変数がどのようにメモリを使うのかで考えた方が意外に分かりやすいものです。
さて、今回はクラスの特徴的機能である「継承」について説明します。継承はJavaをはじめとするオブジェクト指向言語の代表的概念ですが、初学者には最初の壁となって立ちはだかります。まず、クラスについておさらいしましょう。
- クラスには、メンバ変数としてプリミティブ型やほかのクラス型変数を要素として格納できる。
- クラスのインスタンスを生成すると、メンバ変数を格納するのに必要なサイズのメモリ領域が確保される。
前回は地図上の地点を表現するクラスとして、次のようなクラスを作りました。
class GeographicInfo { |
GeographicInfo型のクラスには、経度と緯度を表現するためにdouble型のlatitude(緯度)とlongitude(経度)というメンバ変数が定義されています。GeographicInfo型のクラスを使うことで、ある場所の経度と緯度を別個の変数として管理しなくてもよくなります。しかし、プログラムに修正はつきものです。経度と緯度のほかに高度も扱いたくなったとしたら、どうしたらよいでしょうか。最も簡単な解決策は、別のクラスを新しく定義することです。
class GeographicInfo3D { |
この方法のデメリットは、GeographicInfo型を使って作った既存のプログラムと互換性がなくなることです。GeographicInfo型とGeographicInfo3D型はまったく関係のない別のクラスですので、元のコードとの互換性を保つには、ソースコードをすべて変更して、GeographicInfo3D型に置き換えなくてはいけません。
別のデメリットもあります。GeographicInfoとGeographicInfo3Dは別のクラスですが、違いは「double height;」の1行だけです。これでは、クラス定義の3分の2が重複していることになります。複雑なクラスであれば、メンバ変数を1つ追加するためによく似たクラスを定義することの無駄はもっと多くなります。
| クラスの継承とは定義の流用である |
そこでJavaのクラスには、「継承」という機能が用意されています。まずは実際のソースコードを見てみましょう。
class GeographicInfo3D
extends GeographicInfo { |
クラスの継承は、クラスの定義として「extends <元になるクラス名>」という文と追加するメンバ変数を実際に定義するだけです。
それでは実際に2つのクラスを使ったプログラムを作ってみましょう。
GeographicInfo3Dクラスを使うプログラム class GeographicInfo { |
ちょっと長めのプログラムですが、やっていることは3つしかありません。まず、最初のブロックでは、GeographicInfo型のクラスを定義しています。次のブロックでは、GeographicInfo型を継承してGeographicInfo3D型を定義しています。最後のブロックはプログラム本体で、GeographicInfo3D型のインスタンスを変数gに代入し、メンバ変数latitude、longitude、heightに値を代入して画面に表示しています。それでは、念のためこのプログラムを実行してみましょう。
C:\DOCUME~1\MYDOCU~1\MYJAVA~1>java
UsingGeographicInfo3D
|
GeographicInfo3Dでは、メンバ変数としてheightだけを宣言しており、latitude、longitudeという変数を定義していません。その代わりに、GeographicInfo3D型がGeographicInfo型を継承している、と定義しています。そのため、GeographicInfo3D型の変数gを使って、GeographicInfo3D型で直接定義されていないlatitude、longitudeの値を表示できるわけです。
Javaでは、GeographicInfo型のように元になるクラスのことを「スーパークラス」、GeographicInfo3D型のように元になるクラスの定義を流用する側のクラスを「サブクラス」と呼びます。また、正式なJava用語ではありませんが、スーパークラスのことを「親クラス」や「基底クラス」あるいは「継承元クラス」、サブクラスのことを「子クラス」や「派生クラス」という場合もあります。
クラスを継承すると、スーパークラスで定義したメンバ変数などをサブクラスで流用できるというメリットがあります。同じようなクラスを定義しなくてはならないが、微妙に異なるという場合は、まずすべてのクラスに共通する要素をスーパークラスで定義し、異なる部分だけを個別のクラスとして定義することで、プログラムを効率的に開発しましょう、というのがオブジェクト指向の基本的な考え方の1つとされています。
| クラスを継承すると何が起きるのか |
クラスの継承は元のクラスを流用することです。ところが「Java入門」といった書籍や記事を読むと、次のような「例え話」が出てきます。
![]() |
| ありがちなクラス継承の説明図 クラスの継承とは、「電気製品」クラスを継承して「テレビ」クラスを作り、「テレビ」クラスを継承して「カラーテレビ」クラスを作るといったように、サブクラスがスーパークラスの性質を受け継ぐことである |
特にどの本というわけではないのですが、どうしてこういう例え話が出てきてしまうのか、私にはさっぱり分かりません。クラスの概念を哲学用語か何かのように説明するのはいいかげんやめにしてほしいものです。だいたい、テレビ型やカラーテレビ型クラスを作るJavaプログラマがどれだけいるというのでしょう。しかも、第2回「Javaの変数の本質を知る」で指摘した「変数は箱だ」説同様、この手の例え話を信じると、プログラムがどのようにメモリを使うのかという視点が抜け落ちてしまいます。
そこで、クラスの継承がどのようにメモリを使うのか見てみましょう。まず、スーパークラスとなるGeographicInfo型のインスタンスは次のようにメモリを使います。
![]() |
| GeographicInfo型のインスタンスが使うメモリ領域 |
GeographicInfo型にはdouble型のメンバ変数latitudeとlongitudeが含まれますので、全部で16bytesのメモリを消費します。一方、GeographicInfo 型のサブクラスであるGeographicInfo3D型は、GeographicInfo 型にdouble型のメンバ変数heightを追加定義したものです。GeographicInfo3D型のインスタンスは次のようにメモリを使います。
![]() |
| GeographicInfo3D型のインスタンスが使うメモリ領域 |
GeographicInfo3D型の定義ではメンバ変数heightだけが宣言されていますが、GeographicInfo3D型はGeographicInfo 型のサブクラスです。従ってGeographicInfo3D型のインスタンスは、スーパークラスであるGeographicInfo型の16bytesにメンバ変数heightの分8bytesを加えて合計24bytesのメモリを消費します。
いかがでしょうか。例え話を使った継承の説明では、こういう視点にたどり着くまでにずいぶん時間がかかります。そもそも、継承を示すキーワードである「extends」は「延長する」という意味です。クラスの継承とは「使用メモリ量の付け足しだ」と思えば理解はずいぶん早まるはずです。
| クラス継承の理解を深める |
クラスを継承させるメリットは、クラス間の関係をプログラムの中に埋め込めることです。初めに説明したように、GeographicInfo型とGeographicInfo3D型をまったく独立して定義することもできますが、GeographicInfo型からGeographicInfo3D型を継承させることで、2つのクラス間の関係まで定義できるのです。このことを確かめるために、次のプログラムを実行してみてください。
GeographicInfo3D型のインスタンスをGeographicInfo型として扱うプログラムclass GeographicInfo { |
このコードを実行すると以下のような結果になります。
C:\DOCUME~1\MYDOCU~1\MYJAVA~1>javac
SubAsSuper.java |
初めに紹介したプログラムとよく似ていますが、決定的に異なるのは、スーパークラスであるGeographicInfo型の変数gを使ってGeographicInfo3D型として生成したインスタンスのメンバ変数latitudeとlongitudeの値を表示していることです。どういうことでしょうか。
まず、「g = h;」という文によって、gにもhにも「new GeographicInfo3D()」という文で生成されたGeographicInfo3D型のインスタンスの先頭アドレスが格納されます。gはGeographicInfo型ですので、GeographicInfo3D型固有のメンバ変数であるheightにはアクセスできません。しかし、先頭から16bytesまでにあるlatitudeとlongitudeにはアクセスできるわけです。
このことをクラス継承の例え話で理解するのはかなり厄介です。「カラーテレビ型はテレビ型の性質を受け継いでいるから、カラーテレビ型のインスタンスはテレビ型のインスタンスとしても扱える」といわれても、テレビの説明をしたいのかプログラミング言語の話をしたいのかさっぱり分かりません。
クラスの継承の基本は「使用メモリ領域の付け足し」ですので、サブクラスのインスタンス化によって確保されたメモリ領域をスーパークラスのインスタンスとして扱えるのは当たり前と考えるべきなのです。
さて、今回まで「変数はメモリをどのように使うのか」という視点でJavaを解説してきました。クラスについて説明をし尽くしていませんが、これ以上はメモリ領域の面だけでは解説できません。そこで次回からは制御文や関数の説明に入ります。
いまから始めるJava バックナンバー
- 第1回 Java2 SDKで学習の準備
- 第2回 Javaの変数の本質を知る
- 第3回 クラスを簡単に理解しよう
- 第4回 クラスの継承の本質を知る
- 第5回 メソッドとコンストラクタはなぜ必要?
- 第6回 Javaプログラムの制御構造を理解する
- 第7回 Javaの制御文を使いこなそう
- 第8回 メソッドの挙動を変えるオーバーライド
- 第9回 クラスのメンバに利用制限を付与するアクセス制御
- 第10回 Javaのクラスをグループ化するパッケージ
- 第11回 Javaのクラスの理解を深める
- 第12回 Javaプログラミングにおけるエラー対処
- 第13回 Javaの例外をスマートに記述する
- 最終回 Javaの抽象クラスとインターフェイス
| 「いまから始めるJava」記事一覧 |
ホワイトペーパー(TechTargetジャパン)
- Webの表示速度を遅くする「SSLハンドシェイク」とは (2010/2/9)
安全性を担保しようとWebページにSSLを適用すると、負荷の高い処理が実行される。速度と安全性は両立できるのか? - クラウド活用「雲活」のために押さえるべき39のポイント (2010/2/2)
活用するべきサービスか否か、クラウドの利点・問題点、クラウドプラットフォーム提供企業になるための条件、開発者がするべきことに分けて紹介 - 再利用性の高いクラス作成に重要な“アクセス制御” (2010/1/28)
Javaのアクセス修飾子public、private、protectedや、Eclipseで簡単に作れるアクセサメソッドgetter、setterについて解説 - DB設計の神ツール「ERMaster」なら、ここまでできる (2010/1/21)
直感的なUIに、カスタマイズ可能な、Excel出力のテーブル定義書、辞書機能など多機能なERモデリングの無料Eclipseプラグインです
|
|
スキルアップ/キャリアアップ(JOB@IT)
スポンサーからのお知らせ
- - PR -
- - PR -
お勧め求人情報

**先週の人気講座ランキング**
〜CCNA編〜
| ◆ | 企業の仮想化に足りない“発想”とは? 仮想化運用管理のキモは意外なところに! New! |
| ◆ | 操作もマニュアルも分かりやすい! ユーザー視点で開発されたPC管理ツール New! |
| ◆ | 仮想化すればコストは削減できるか? 仮想化に必要な「3つの視点」を解説する |

| ◆ | セキュリティを知り尽くす上野氏が登壇! @ITメールソリューションLive! in Tokyo |
| ◆ | 運用管理の課題を“2つの観点”から分析 ユーザー満足度の高い「仮想環境」とは? |
| ◆ | 世界に通用するストレージの作り方とは? 製品に込めた思いを富士通の開発者に聞く |

| ◆ | OSSで手間も時間も、障害も減った―― 「マピオンの事例」オープンソース活用法 |
| ◆ | 「ノートPCの持ち出し禁止」で大丈夫? 情報漏えいを防ぐ管理手法とインフラは? |
| ◆ | 1日の処理を1秒に――MySQLの達人が語る 「コスト削減」できるチューニング |

| ◆ | ドキュメント作成を自動化して、SEの作業 効率を大幅アップ! Visio 2007の魅力 |
| ◆ | 急速に広がるHyper-Vでのサーバ仮想化 そのベストプラクティスをデルが解説 |
| ◆ | @IT主催セミナーで語られた、「担当者に 求められるセキュリティ対策」をレポート |

| ◆ | @IT「Windows 7」 特設サイトオープン! 最新情報・移行ノウハウを公開しています |









