|
では実際に継承のプログラミングを練習してみましょう。サンプルとして利用するコードはObjectを除く以下の6つです。クラス名をクリックするとソースコードをダウンロードできます。
ExtTestMain系のクラスに関してはコメントを読めばわかるので説明は省略します。実際の継承用のクラスの関係としては下図のように、ExtTestSuperを親クラスとして、その下にExtTestSub1、ExtTestSub2が子クラスとして存在ます。さらにExtTestSub1を継承して
ExtTestSub1_subが孫クラスとして存在しています。
まずExtTestSuperクラスのソースを見てみましょう。もちろんJavaDocもあわせて見て下さい。このクラスは名前と電話番号を表すString型の変数を内部に保持するクラスです。両変数ともにコンストラクタによって初期値を設定することができます。nameはpublicなアクセスが可能なので直に書き換えることができます。またtelはprivateアクセスなのでsetTelやgetTelメソッドによって書き換えや取得を行います。
|
例:ExtTestSuper.java
|
| |
|
|
| |
/**
継承の実習サンプルプログラム:親クラス
@author Fumitaka Makino
*/
public class ExtTestSuper extends java.lang.Object{
/** 名前 */
public String name = null;
/** 電話 */
private String tel = null;
/**
コンストラクタ、名前と電話番号を引数に持つ
@param String sname 名前
@param String stel 電話番号
*/
public ExtTestSuper( String sname , String stel ){
this.name = sname;
this.tel = stel;
}
/**
電話番号を取得する
@return String 電話番号
*/
public String getTel(){
return this.tel;
}
/**
電話番号を設定する
@param String stel 電話番号
*/
public void setTel( String stel ){
this.tel = stel;
}
}
|
|
| |
|
|
|
注目してほしいのが「public
class ExtTestSuper extends java.lang.Object{」の部分です。extendsとは自分が何のクラスを継承しているかを表す予約語です。つまりこのクラスはObjectクラスを継承していると言うことになります。通常のクラス宣言では「public
class ExtTestSuper{」と記述すれば自動的にObjectクラスを継承したことになります。もちろん、java.lang.Object以外のクラスを継承するときには、下記のようにクラス名の後ろに明示的に継承元のクラス名を記述してやる必要があります。
public class クラス名 extends 継承元のクラス名
{
ではここで単純にExtTestSuperクラスを継承したExtTestSub1クラスを見てみましょう。このクラスはコンストラクタの再宣言以外は何もやっておらず、そのまま親クラスの「資産を相続」しています。
|
例:ExtTestSub1.java
|
| |
|
|
| |
/**
継承の実習サンプルプログラム:子クラス1
@author Fumitaka Makino
*/
public class ExtTestSub1 extends ExtTestSuper{
/**
コンストラクタ、名前と電話番号を引数に持つ。内部ではスーパークラスのコンストラクタを実行している。
@param String sname 名前
@param String stel 電話番号
*/
public ExtTestSub1( String sname , String stel ){
//スーパークラスであるExtTestSuperのコンストラクタを実行
super( sname , stel );
}
}
|
|
| |
|
|
|
ここで見てほしいのがコンストラクタの部分です。「super(sname,stel)」と記述してありますね。コンストラクタはクラス名で宣言されているため単純に継承できません。そのため親クラスのコンストラクタをこのように呼び出して初期化しているのです。
次に単純に継承するのではなく、相続した資産の一部を変更してしまう(オーバーライド:上書き)というコードを見てみましょう。
|
例:ExtTestSub2.java
|
| |
|
|
| |
/**
継承の実習サンプルプログラム:子クラス2
@author Fumitaka Makino
*/
public class ExtTestSub2 extends ExtTestSuper{
/**
コンストラクタ、名前と電話番号を引数に持つ。内部ではスーパークラスのコンストラクタを実行している。
@param String sname 名前
@param String stel 電話番号
*/
public ExtTestSub2( String sname , String stel ){
//スーパークラスであるExtTestSuperのコンストラクタを実行
super( sname , stel );
}
/**
電話番号を取得する。オリジナルのgetTelメソッドをオーバーライド(上書き)しています。
オリジナルではセットした電話番号をリターンしていますが、このメソッドでは冒頭に「TEL:」
を付加するように変更してあります。
@return String "TEL:" + [電話番号]
*/
public String getTel(){
return "TEL:" + super.getTel();
}
}
|
|
| |
|
|
|
コンストラクタに関してはExtTestSub1と同一でsuperを呼び出しているだけですね。注意してほしいのがgetTelメソッドです。このメソッドはオーバーライドされておりExtTestSub2のインスタンスのgetTelを実行すると、このメソッドが呼ばれます。ExtTestSub2のgetTelは親クラスのgetTelの戻り値に「TEL:」という文字列を付加してリターンしています。
オーバーライドの条件は、メソッド名、引数ともに親クラスのメソッドと同一のメソッドを実装していることです。JavaのVMは、実行時にメソッドを呼び出すときにクラスを継承の順を遡って(サブクラスからスーパークラスへと)探していきます。またメソッド名のみ同じメソッド(*)を実装することをオーバーロードと言います。
*あたりまえですが戻り値のみ違うメソッドは実装することができません。なぜなら呼び出す側がメソッドを区別できないからです。
最後にExtTestSub1を継承したExtTestSub1_subを見てみましょう。
|
例:ExtTestSub1_sub.java
|
| |
|
|
| |
/**
継承の実習サンプルプログラム:子クラス1のサブクラス
@author Fumitaka Makino
*/
public class ExtTestSub1_sub extends ExtTestSub1{
/**
コンストラクタ、名前と電話番号を引数に持つ。内部ではスーパークラスのコンストラクタを実行している。
@param String sname 名前
@param String stel 電話番号
*/
public ExtTestSub1_sub( String sname , String stel ){
//スーパークラスであるExtTestSuperのコンストラクタを実行、名前の引数に変更を加える
super( "[ "+sname+" ]" , stel );
}
}
|
|
| |
|
|
|
このクラスはExtTestSub1と同様にメソッドやフィールドなどの変更はしていません。しかしコンストラクタの部分を見てください。親クラスのコンストラクタを呼び出すときに引数に手を加えています。それ以外の振る舞いはExtTestSub1と全く同一のクラスです。
ではこの継承関係を「型の遺伝」を通して考えてみましょう。下表を見て下さい。
|
表:型のくくり
|
|
型
|
この型に属するクラス名
|
| ExtTestSuper |
ExtTestSuper、ExtTestSub1、ExtTestSub2、ExtTestSub1_sub |
| ExtTestSub1 |
ExtTestSub1、ExtTestSub1_sub |
| ExtTestSub2 |
ExtTestSub2 |
| ExtTestSub1_sub |
ExtTestSub1_sub |
|
今回作成した全てのクラスはExtTestSuperを継承、もしくは間接的に継承しています。そのため全てがExtTestSuper型として扱うことが可能です。またExtTestSub1型にはExtTestSub1クラスとそれを継承したExtTestSub1_subクラスが含まれます。あとの二つはサブクラスを持たないので、それぞれ所属しているクラスは一つとなります。
以上、これらのクラスを実際に利用しているクラスがExtTestMain1とExtTestMain2となりますのでソースコードをよく参照してください。
|