Java学習ノート_140714_2（継承）

# 継承（クラスとオブジェクト）

オブジェクト指向プログラミング（OOP）とは、データとその操作方法を一緒にしたオブジェクト（Javaの場合はクラス）を利用したプログラム技法のこと。Smalltalkのアラン・ケイ（名付け親）とC++のビャーネ・ストロヴストルップ（特徴を再定義）が影響を与えたと言われる。

### 特徴

1. カプセル化
2. 継承
3. ポリモーフィズム（多態性）

カプセル化については、アクセス修飾子とかセッタゲッタ（どうでもいいけど、雪駄下駄って出ると日本だなぁって思う）あたりで半分くらいは理解できてる気がするので、継承から進むようだ。

継承は、クラスの機能を他のクラスが引続ぐ仕組み。親子のような関係。継承元をスーパークラス（親クラス）、継承するクラスはサブクラス（子クラス）。継承を用いて、同一の機能を省略していく記述方法を差分プログラミングと呼ぶ。

スーパークラスから継承したメソッドを上書きすることを、メソッドのオーバーライド（再定義）と呼ぶ。オーバーロード（多重定義）は同一クラス内の引数の異なるメソッドを複数定義すること。ライドでスーパークラスに乗るイメージ、とのこと。

フィールドの再定義はオーバーライドとは呼ばない。ポリモーフィズムは単に上書きのことを言うわけではない。staticメソッドの再定義もできるが、あまり推奨はされない。

上記機能を試してみた。

```java:Animal.java
/*
 *  動物クラス
 */
public class Animal {
	String favorite = "worm";

	void sleep(){
		System.out.println(getClass().getName() + " is sleeping normally now..." );
	}
}
```

```java:Ape.java
/*
 *  猿クラス（動物クラスから継承）
 */
public class Ape extends Animal{
	String favorite = "banana";

	void sleep(){
		System.out.println("Ape is sleeping on the tree now.....");
		super.sleep();
	}
}
```

```java:Human.java
/*
 *  人間クラス（猿クラスから継承）
 */
public class Human extends Ape {
	String favorite = "beef";
	String item = "PC";

	void sleep(){
		System.out.println("Human is sleeping on the bed now.....");
	}
	void eatAndSleep(){
		System.out.println(getClass().getName() + " is eating " + favorite +"." );
		sleep();
		super.sleep();
	}
}
```

```java:OOPSample.java
public class OOPSample {
	public static void main(String[] args) {

		Animal animal = new Animal();
		System.out.println("### " + animal.getClass().getName() + " ###");
		//System.out.println(animal.favorite);
		animal.sleep();

		Ape ape = new Ape();
		System.out.println("### " + ape.getClass().getName() + " ###");
		//System.out.println(ape.favorite);
		ape.sleep();

		Human human = new Human();
		System.out.println("### " + human.getClass().getName() + " ###");
		//System.out.println(human.favorite);
		human.eatAndSleep();
	}
}
```

実行結果

```
### Animal ###
Animal is sleeping normally now...
### Ape ###
Ape is sleeping on the tree now.....
Ape is sleeping normally now...
### Human ###
Human is eating beef.
Human is sleeping on the bed now.....
Ape is sleeping on the tree now.....
Human is sleeping normally now...
```

### オーバーライドの制限

final修飾子がついたメソッドはオーバーライドできない。また、オーバーライドした際、元のメソッドで定義されているアクセス修飾子と同じか、またはゆるい宣言でなければならない。スーパークラスでprivateのメソッドは継承できない。同じシグネチャのメソッドを定義できるが、別メソッドの定義として扱われる。

スーパークラスのstaticなメソッドと同名の非staticなメソッドをサブクラスで定義することができない。非staticメソッドをstaticメソッドでオーバーライドすることもできない。throwsによる例外宣言も継承できるが、限定的な形になる（例外をなんでもスローできるわけではない）。


### final修飾子

final修飾子をつけることで、クラス、また個別のメソッドの継承を禁止することができる。フィールドにfinal修飾子をつけた場合は、オーバーライドと継承を禁止するということではなく、代入（または初期化）時の値を変更できないということを表す。

### 継承とコンストラクタ、super()

**コンストラクタ（他にはprivateなメンバ）は継承されない。**コンストラクタ内で`super()`を宣言すると、スーパークラスのコンストラクタを明示的に呼び出すことができる。superはコンストラクタ内で最初に呼び出される必要がある（あとにするとエラーが出る、納得）。

### is or has

isで考えられる場合は継承関係、hasの場合は、メンバとして考えると、実装のときに迷わないらしい。

## 問題

メンバにwidth, height getArea()を持ったRectクラスを継承した、Cubeクラスで奥行きdepthと体積を求めるgetVolumeを定義して使用するサンプルを作成する。

```java:Rect.java
public class Rect {
	int width, height = 0;
	public int getArea(){
		return width * height;
	}
}
```

```java:Cube.java
public class Cube extends Rect {
	int depth = 0;
	public int getVolume() {
		return getArea() * depth;
	}
}
```

```java:CubeSample.java
public class CubeSample {
	public static void main(String[] args) {
		Cube cube = new Cube();
		cube.width = 10;
		cube.height= 20;
		cube.depth = 30;
		System.out.println(cube.getVolume());
	}
}
```

より整理して書くと以下。

```java:Rect.java
class Rect {
	int width, height = 0;
	Rect(int x, int y) {
		width = x;
		height = y;
	}
	int getArea(){
		return width * height;
	}
}
```

```java:Cube.java
 class Cube extends Rect {
	int depth = 0;
	Cube(int x, int y, int z) {
		super(x, y);
		depth = z;
	}
	public int getVolume() {
		return getArea() * depth;
	}
}
```

```java:CubeSample.java
public class CubeSample {
	public static void main(String[] args) {
		Cube cube = new Cube(10,20,30);
		System.out.println(cube.getVolume());
	}
}
```