初心者のJavaプログラミング

プログラミングガチ初心者がIT業界を目指して頑張ります。

【第21回】初心者のJavaプログラミング【継承と変数•オーバーライド•コンストラクタ】

継承において、スーパークラスの属性やメソッドはサブクラスが相続します。
つまり、サブクラスではスーパークラスの属性やメソッドが使えます。
前々回あたりにやりました。

継承と変数

スーパークラスと同じ名前の変数をサブクラスで作った場合はどうなるでしょうか。
この場合は、サブクラスで作った変数がスーパークラスの変数を隠してしまいます。
となると、スーパークラスの変数はサブクラスから参照することができない!
と思いきや、やっぱりちゃんとサブクラスから参照できる機能がJavaにはあるんですね。
superというキーワードを使うと出来ます。
super.変数名
というようにサブクラス内で使用すれば、スーパークラスの同じ名前の変数を参照することが出来ます。
注意点ですが、2つ上のスーパークラスの変数にはアクセスできません。
super.super.変数名
といった使い方は出来ないということです。

そんじゃいつもの通り例を。

class Goku {
	// 悟空の身長と体重
	double height = 180.;
	double weight = 70.;
}

class Gohan extends Goku{
	// ご飯の身長と体重
	double height = 170.;
	double weight = 60.;
	// 悟空の身長を参照
	double getGokuHeight() {
		return super.height;
	}
}

class GokuGohan {
	public static void main(String[] args) {
		Gohan gohan = new Gohan();
		
		System.out.println(gohan.height);
		// サブクラスの悟飯から悟空の身長を呼び出す。
		System.out.println(gohan.getGokuHeight());
	}
}

メソッドのオーバーライド

同じシグネチャを持つメソッドスーパークラスにもある場合、スーパークラスメソッドが実行されずに、サブクラスのメソッドが実行されます。
シグネチャとは前もやりましたが、
メソッド名、引数の数、引数の型の組み合わせのことです。注意点ですが、戻り値の型はシグネチャに含まれません!
このことを知らなくて、なんかの問題ができませんでしたw

これは具体的な例を見た方が分かりやすいので、例を出します。

class Goku {
	void kamehameha() {
		System.out.println("おら悟空。カメハメ波!!");
	}
}

class Gohan extends Goku{
	void kamehameha() {
		System.out.println("ひゃっほーおら悟飯。カメハメ波!!");
	}
}

class GokuGohan {
	public static void main(String[] args) {
		Goku goku = new Goku();
		goku.kamehameha();

		Gohan gohan = new Gohan();
		gohan.kamehameha(); //< オーバーライド

		// 要注意!!
		Goku test = new Gohan();
		test.kamehameha(); //< オーバーライド
	}
}

mainメソッド内の、
Gohan gohan = new Gohan();
というところがオーバーライドです。
スーパークラスのkamehameha()メソッド
サブクラスのkamehameha()メソッド
シグネチャが同じですよね。
なので、スーパークラスのkamehameha()ではなく、
サブクラスのkamehameha()が呼ばれます。

問題は一番したのやつです。
Goku test = new Gohan();
です。
変数の型はスーパークラスであるGokuですね。
ですがオブジェクトそのものの型はGohanですよね。
どのkamehameha()メソッドを実行するのかを決定するのは、
変数の型ではなく、オブジェクトそのものの型です。
なのでこの場合はGokuではなく、Gohanのkamehameha()が呼ばれることになります。

new コンストラクタ()でオブジェクトの参照が渡されることを思い出せば普通に理解できますが、
勘違いしやすいところです。
気をつけましょう!!

ちなみに、メソッドも変数と同じく、
super.メソッド名();
というかたちで、スーパークラスメソッドを使用できます。

継承とコンストラクタ

クラスの属性とメソッドはそのクラスだけではなく、スーパークラスにも定義されています。
なので、そのクラスだけコンストラクタを実行して初期化するだけだと、適切な初期化が出来ません。
また、スーパークラスで定義された属性とメソッドはサブクラスのコンストラクタを実行する前に、適切に初期化されてなければなりません。
つまり、スーパークラスコンストラクタがサブクラスのコンストラクタより先に実行されることになります。

ここは、そうなんだーと思って検証してみるくらいでいいのかなって思います。


以上でクラス関係の所は終了です。
あとは、クラスの修飾子(publicとかprivateとか)は時間があるときに確認する感じでいいと思います。
余裕があれば書いていきますが、最近余裕がなくなってきたので厳しいかもですw


次からはインターフェイスに入ります。