オブジェクト指向プログラミングa 『クラスの継承 (前編)&(中編)』〜 11.継承のポイント |
参考資料:「Javaを学ぶ 第10回 (2003年2月 )」,「Javaを学ぶ 第11回 (2003年3月 )」
●ここで継承のポイントをまとめる。
【1】既にあるクラスの挙動をカスタマイズした新たなクラス(サブクラス)を手軽に作成できる。
・継承により,スーパークラスの性質や能力(すなわちメンバ)を手に入れられる。
・スーパークラスには無いメンバ(フィールドやメソッド)を新たに追加できる。
・継承したメソッドの挙動をサブクラス独自のものに変更できる(オーバライド)。
例1ウィンドウを表すJFrameを継承し,ウィンドウを開くときに徐々に大きくなるようにカスタマイズしたサブクラスを作成する。 |
MyJFrame.java 下のソースコード画像にマウスカーソルを重ねると解説が表示されます。 |
【2】共通の性質をもったスーパークラスを作成し,そのスーパークラスを使ってソフトウェア
の大部分を書けば,汎用性のある(=将来的に変更が少なくて済む)ソフトウェアを作成できる。
・まず,適切なスーパークラスを考える。
・そのスーパークラスを使ってソフトウェアの大部分を書く。
・バリエーションが必要な時は,サブクラスを使ってメソッドを適切にオーバーライドする。
・サブクラスのオブジェクトは,スーパークラスで書かれたプログラムに処理させることができる。
これが,ここまで学習してきた継承の最重要なメリットである。
(本編で詳しく説明したので,ここでは図などは示さない。)
【3】メソッドの仮引数型を見たとき,そのサブクラスのオブジェクトも実引数として渡せること
を意識すること。
【4】あるクラスのメソッドやフィールドは,そのスーパークラス(もしくは,その更にスーパークラス)
から継承したものかもしれない,ということを意識すること。
調べるときは,スーパークラスに
さかのぼって調べたりします(Javaのマニュアルドキュメントなどが役立ちます)。
実例:
ウィンドウを表す JFrame 型には,ウィンドウの大きさを設定・変更するメソッド setSize( ) があるのは今までの例でご存じだと思うが,
この setSize( ) メソッドは,スーパークラスのスーパークラスである java.awt.Window から継承したメソッドなのである(下図参照)。
JFrame クラスのマニュアルはここにあるが,そのページにも java.awt.Window クラスから継承したメソッドの一覧が載っている。
【5】前項とは逆に,あるクラスに便利なメソッドやフィールドがある事を知ったなら,そのすべてのサブクラスも
その便利なメソッドやフィールドが使える,ということになる。(マニアックな注意書きを読みたければ画像をクリック)
実例:
Javaのクラスすべてのスーパークラスである Object には様々なメソッド(やフィールド)が定義されている。
つまり, Java に元から用意されているクラスではすべて,それらのメソッドが使えるということになる。
実際,Java に用意されているクラスは,それらのメソッドを必要に応じてオーバライドしてちゃんと使えるように用意している。
Objectクラスで定義された数あるメソッドの中でも便利なのものに,toString( ) メソッドがある。このメソッドはそのオブジェクト
の文字列表現をString型オブジェクトで返してくれる。しかも,文字列(String型オブジェクト)が必要な局面で使うと,自動的に呼ばれるという特別なメソッド
なのである。
以下にその使用例を示す。
import javax.swing.JFrame; class A { } class B{ String str; B( String str ) { this.str = str; } public String toString() { // toString( )メソッドを,フィールドstrの値を返すようにオーバライド return str; } } public class ToStringSample { public static void main(String[] args) { JFrame f = new JFrame( ); f.setSize( 200, 50 ); f.setVisible( true ); System.out.println( f ); // println( ) メソッドの仮引数型はString型なので,自動でfのtoString( )メソッドが呼ばれる。 System.out.println( f.toString() ); // toString( )メソッドを明示的に呼んでみる。表示結果は前行と同じ。 A a = new A(); System.out.println( a ); // println( ) メソッドの仮引数型はString型なので,自動でaのtoString( )メソッドが呼ばれる。 System.out.println( a.toString() ); // toString( )メソッドを明示的に呼んでみる。表示結果は前行と同じ。 B b = new B( "Good!" ); System.out.println( b ); // println( ) メソッドの仮引数型はString型なので,自動でbのtoString( )メソッドが呼ばれる。 System.out.println( b.toString() ); // toString( )メソッドを明示的に呼んでみる。表示結果は前行と同じ。 } }
・20行目と21行目で,JFrame型オブジェクト f の toString( ) メソッドを呼んでいる。JFrame型オブジェクトの内部情報が表示されるのが分かるはずである。
20行目は,toString( )メソッドの仮引数が文字列(String型オブジェクト)なので,自動的に toString( )メソッドが呼ばれていることに注意せよ。
21行目は,
明示的にJFrame型オブジェクト f の toString( ) メソッドを呼んでいる。20行目の表示結果と同じであることを確認せよ。
このように,JFrame型の toString( ) メソッドは,オブジェクトの内部情報を表示するようにオーバライドされている。
・それでは,素のままの toString( )メソッドはどのような文字列を返すのだろうか。次にそれを見てみよう。
・24行目と25行目で,自作クラスA の toString( ) メソッドを呼んでいる。クラス A の toString( ) メソッドは,Objectクラスからそのまま継承したものである。
実際に実行してみると,
クラス名@ランダムな文字列
という内容が表示される。 @の後のランダムな文字列は,その時点で生成されているオブジェクトひとうひとつに割り当てられた値で ,Javaの内部処理で利用される値である。
24行目は,toString( )メソッドの仮引数が文字列(String型オブジェクト)なので,自動的に toString( )メソッドが呼ばれていることに注意せよ。
25行目は,
明示的にA型オブジェクト a の toString( ) メソッドを呼んでいる。24行目の表示結果と同じであることを確認せよ。
・
では,今度は toString( ) メソッドをオーバライドしてみよう。
・28行目と29行目で,自作クラス B の toString( ) メソッドを呼んでいる。クラス B の toString( ) メソッドは,オーバライドによって,String型フィールド str
の内容を返すようになっている。
実際に実行してみると,フィールド str に設定されている文字列が表示されることが分かる。
28行目は,toString( )メソッドの仮引数が文字列(String型オブジェクト)なので,自動的に toString( )メソッドが呼ばれていることに注意せよ。
29行目は,
明示的にB型オブジェクト b の toString( ) メソッドを呼んでいる。29行目の表示結果と同じであることを確認せよ。
・通常は,JFrame や 上記の自作クラス
B のように,toString( ) メソッドをオーバライドし,そのオブジェクトの内容を表す適切な文字列を返すように定義するのが望ましい。