Java オブジェクト指向プログラミング ステップ2(継承)

右は、『 Recoed2クラスを継承したRecord3のクラスがある』というのクラス図です。

Recoed2クラスを継承したRecord3クラスは、Recoed2クラスの派生クラスと呼ばれます。

Record2の派生クラスは、Record2の情報と機能をそっくり、受け継いだクラスです。
Record3は、Record2のshoとsuuと情報があり、displayメソッドなどのたくさん機能が使え、 それに加えてpublic のint型フィールドtankaが存在するクラスであることを示しています。

クラス図の、白の△で示す矢印で、この継承関係を表現します。
(矢印先のRecoed2クラスを継承して、Record3クラスがある)
この時、Record2をRecord3のスーパークラス Record3をRecord2のサブクラスまたは派生クラスと呼びます。

以下にRecord3.javaのコードを示します。
同じrecパッケージ指定なので、 Recoed3.javaも、Record2.javaと同じrecディレクトリの中に作ります。
次のようにRecord3のクラスを作る時、extends キーワードの後にRecord2を指定します。これで、 Record2を継承したクラスになります。
そして、新たにpublic のフィールドとしてint型のtankaを宣言するだけです。

package rec;

public class Record3 extends Record2
{
	public int tanka;	//単価
}

なお、rec以外のpackageに所属させることもできますが、ここでは同じにしました。 これによりに先頭で、import rec.Record2;の記述が不要になります。 (他のpackageに所属させる場合は必要になります。)

以下のプログラムで、Record3クラスを利用例を示します。(右が実行結果です。)

import rec.Record3;

public class Test
{
	public static void main(String[] arg){
		Record3 r1 = new Record3();
		//レコード2のコンストラクタが内部で実行されいる。
		
		r1.init("A01", 10);//Record2の機能を利用
		r1.tanka = 100;

		r1.display(1);//Record2の機能を利用
		System.out.printf("\t単価:%d\n", r1.tanka);
	}
}

D:\java>java Test
   1番目レコード
        商品コード:A01
        数量:10
        単価:100
        
D:\java>







さて、 上記  の2行は、 Record3専用のinitメソッドを作ることで1行で済ませることができます。
同様に上記  の2行は、 Record3専用のdisplayメソッドを作ることで1行で済ませることができます。
以下で、そう変更したRecoed3.javaとクラス図を示します。


package rec;

public class Record3 extends Record2
{
  public int tanka;	//単価

  public void init(String shoCode, int n, int price)
  {
    super.init(shoCode, n);// スーパークラスのinitを呼び出す
    //この場合はsuperを省略できます
    
    tanka = price;
  }

  public void display(int n)
  {
    super.display(n);// スーパークラスのdisplayを呼び出す
    //この場合はsuperを省略でません。省略すると、
    //自身を呼び出す(再帰)ため無限ループなり、
    //StackOverflowErrorの実行エラーになる
    
    System.out.printf("\t単価:%d\n", tanka);
  }	
}


Record3でメソッドを追加していますが、 その場合でもなるべくスーパークラスであるRecord2の機能を利用するように作成しています。
メソッドの中で、得にスーパークラスのメソッドを明示的に使いたい場合は、super のキーワードを使います。このsuperキーワードを使わなくても、同じ操作(引数や戻りなど)のメソッドがなければ、 引き継いでいるスーパークラスのメソッドが使えます。
initの場合は、引数2つのinitメソッドが Record3に無いのでsuper.は書かなくてもRecord2のinitメソッドが呼び出せます。
 ( this.init(shoCode, n)と書いた場合も同じで、Record2のメソッド呼び出しになります。)
対して、displayは全く同じ操作(引数や戻りなど)のメソッドがあるので、明示的super のキーワードを使わないと、Record2の機能が呼び出せないことになります。

以下のこのクラスを使うように変更したTest.javaと実行結果を示します。

import rec.Record3;

public class Test
{
	public static void main(String[] arg){
		Record3 r1 = new Record3();
		//レコード2のコンストラクタが内部で実行されいる。
		
		r1.init("A01", 10, 100);//Record3の機能を利用
		
		r1.display(1);//Record3の機能を利用
	}
}

D:\java>java Test
   1番目レコード
        商品コード:A01
        数量:10
        単価:100
        
D:\java>





なお、 上記のプログラムを、次のように実行できるようにするには どうしたらよいでしょうか?

import rec.Record3;

public class Test
{
	public static void main(String[] arg){
		Record3 r1 = new Record3("A01", 10, 100);
		
		r1.display(1);//Record2の機能を利用
	}
}

シンボルを見つけられません。
シンボル: コンストラクタ Record3(java.lang.String,int,int)
new Record3("A01", 10, 100);
の所でコンパイルエラとなります。
つまりRecord3のコンストラクタを追加すればよいのです。
Record3.javaに次のコードを追加すればよいでしょう。

	public Record3(String shoCode, int n, int price)
	{
		super(shoCode, n); // スーパークラスのコンストラクタを呼び出し
		tanka = price;
	}

派生クラスのコンストラクタから、 そのスーパークラス(派生元クラス)のコンストラクタを呼び出す場合は、 上記のように、コンストラクタ内の { 内先頭行で super( 引数 )の 表現で書かなければいけない規則になってます。

また、上記引数ありコンストラクタを作った時より、デフォルトコンストラクタが 使えなくなります。
つまり、new Record3()のような生成ができなくなります。
これは、Record3.javaに次の引数なしコンストラクタのコードを追加することで可能になります。

	public Record3()//引数なしコンストラクタ
	{
		//スーパ(Recoed2)クラスのコンストラクタ書いていなくても実行される。
	}

なお、上記の引数なしコンストラクタや、引数ありコンストラクタで明示的にスーパクラスのコンストラクタを 呼びださない場合は、 書いていなくても自動的にスーパクラスの引数なしコンストラクタが呼び出される 仕組みになっています。
よって この場合、 スーパクラスのRecord2の引数なしコンストラクタが使えるように作られていないと コンストラクタでシンボルを見つけられません。の コンパイルエラーとなり、注意が必要です。
以上のメソッドやコンストラクタ追加により、Record3のクラス図は次のようになります。