継承とオーバーライドで怠惰しよう

継承はねぇ～いいぞぉ～...

学校で僕がだいしゅきな継承が出てきたのでノリと勢いで継承について語りました。
ほとんどアドリブなのでabstractとかも出てきます。

# で、継承ってなんぞや
継承っていうのは他のクラスを取り込むことで、他のクラスに書かれているメソッドとか変数をインスタンス生成あたかも自分のクラスに書かれているメソッドとか、変数のように扱うことができるようになる。

継承をするには`extends`キーワードを使う。
継承されたクラスのことを親クラス（super class）と呼び、継承をし拡張されたクラスのことを子クラス（Sub Class）という。

```java:親クラス
class SuperClass{
  public int num = 10;

  public void superClassMethod(){
    System.out.println("親クラスだよ～");
  }
}
```

```java:子クラス
class SubClass extends SuperClass{
  //とりあえず何も書かない
}
```

```java:mainメソッドを持つクラス
class Test{
  public static void main(String[] args){
    SubClass instance = new SubClass();
    instance.superClassMethod();
  }
}

// >>>「親クラスだよ～」と表示される。
```

図で関係性を表してみるとこんな感じ。
![名称未設定1.png](https://qiita-image-store.s3.amazonaws.com/0/273517/6718ab65-6e82-b145-7248-f3fa3cbce224.png)
子クラスは親クラスを含んでいるような感覚。
日本語で考えると子の中に親？みたいに思うかもしれないけど、頑張って慣れて...

子クラスは親クラスのprivateではない変数もメソッドも使うことができる。
親クラスのprivateな変数などを使いたい場合はGetter・Setterメソッドを用意してやればいい。

```java:子クラス
class SubClass extends SuperClass{
  void test(){
    //親クラスの変数を参照する
    System.out.println(num);  //10

    //親クラスのメソッドを呼んでみる
    superClassMethod();
  }
}
```

こんな感じで継承すると、他のクラスを自分のクラスに取り込んでしまったような感じにすることができた。
けど、いろいろな場所で同じメソッドを使えるというだけならクラスメソッドとかにすればいいじゃーんってね。

<b>そうじゃねぇんだ。</b>

継承すると<b>オーバーライド</b>ができるようになる。やってみよう。

# オーバーライドしてみよう

Override（オーバーライド）をするとスーパークラスのメソッドを上乗せ定義することができる。
なんでそんなことが必要なの？っていうのは後述するからちょっと待っててね。

```java:親クラス
class SuperClass{
  public void printMethod(){
    System.out.println("親クラスだよ～");
  }
}
```

```java:子クラス
class SubClass extends SuperClass{
  @Override
  public void printMethod(){
    System.out.println("オーバーライドしてやったぜ！");
  }
}
```

このように親クラスのメソッドと同じ名前、同じ引数を持つメソッドを子クラスで定義することでメソッドをオーバーライドすることができる。

`@Override`アノテーションというものをメソッドの前に書いている。
これはJavaのコンパイラに対して「このメソッドはオーバーライドしてるんやで」と示すためのもので、プログラムの動作には関係ない。
これがないとオーバーライドしてるかどうかわかんねぇのと、親クラスのメソッドと名前が一致してないとエラーを出してくれるので付けておくのが定石。

詳しいこと知りたくば次のとこを読むとよし。
別にいいや～って人は別に読まなくてよし。

## `@Override`がないとどうなるの？

なんで動作に関係ないものが必要なのか。
例えば、例では`printMethod()`というメソッドを上乗せ定義しているが、ちょっと誤字っちゃって`priiiiiiiiiintMethod()`というメソッド名になってしまったとする。

```java:子クラス
class SubClass extends SuperClass{
  public void priiiiiiiiiintMethod(){
    System.out.println("オーバーライドしてやったぜ！");
  }
}
```

これに`@Override`がついていないと、オーバーライドをしようとしてないメソッドとして普通にコンパイルできてしまう。
このメソッドを呼び出す側でもう一度正確に誤字ってしまう（？）と普通に使えるので、目的の動作をしていないことに気づくのに時間がかかってしまう。

そんなヒューマンエラーを防止するために`@Override`アノテーションを書いた方がよい。
IDEで作業するときなんかは、入力補完機能もよく働いてくれるし。

# なんでこんな面倒くさい事するんだ？
「別に継承したいんだったらコピペなりなんなりしてもう一個クラス作っちゃえばいいじゃん」って、僕も思ったんだけど、継承は僕らが思っているよりもかなりインテリジェンスだ。

## コピペコードを削減できるから
まず、似たクラスを用意する際にコピペせずに済むので、コード量の削減につながる。
「別に長くてもいいじゃん」って？<b>1文字多く打つのもめんどくせぇと思う怠惰になろう！！</b>

プログラム的に生き物を作る例で話を進めていこう。

### 継承せずに書いてみる

```java:お犬さん
class Wanko{
  public void eat(String foodName){
    //犬の食べ方をする処理が書かれていると思って

    //エサ皿に...
    //Direct...
    //Attack!!（犬食い）

    System.out.println(foodName+"食った");

    //消化する
    syouka(foodName);
  }

  public void syouka(String foodName){
    System.out.println(foodName+"消化した");
  }
}
```

```java:おサルさん
class Monkey{
  public void eat(String foodName){
    //サルの食べ方をする処理が書かれていると思って

    //手で拾って...
    //おクチに...
    //運んで食べてほしい。

    System.out.println(foodName+"食った");

    //消化する
    syouka(foodName);
  }

  public void syouka(String foodName){
    System.out.println(foodName+"消化した");
  }
}
```

さて、これら2つのメソッドに似てる箇所がいくつかあるだろう。
これを継承によってコード量を削減していこう。

### 継承して書いてみる

まず、下地となる<b>生き物クラス</b>を作る。
僕は生物学者ではないのでわかんないけど、おサルもお犬も消化する手順は同じものとする。

```java:生き物
class Animal{
  public void eat(String foodName){
    System.out.println(foodName+"食った");

    //消化処理
    syouka(foodName);
  }
  public void syouka(String foodName){
    System.out.println(foodName+"消化した");
  }
}
```

これを継承してお犬さんクラスとおサルさんクラスを書こう。

```java:お犬さん
class Wanko extends Animal{
  @Override
  public void eat(String foodName){
    //犬の食べ方をする処理が書かれていると思って
    //エサ皿に...
    //Direct...
    //Attack!!（犬食い）

    //super()を使うと親クラスのeatメソッドを呼べる。
    super(foodName);
  }
}
```

```java:おサルさん
class Monkey extends Animal{
  @Override
  public void eat(String foodName){
    //サルの食べ方をする処理が書かれていると思って

    //手で拾って...
    //おクチに...
    //運んで食べてほしい。

    //super()を使うと親クラスのeatメソッドを呼べる。
    super(foodName);
  }
}
```

突然`super();`という書き方を出したが、なんてことはない。親クラスのメソッドを呼んでいるだけだ。
<b>親クラスの`eat()`メソッド</b>でお犬とおサルで共通の処理である何を食ったか表示する処理と消化処理をしている。

### ちなみに...（`super()`について）

`super()`はオーバーライドしたメソッドの中、子クラスのコンストラクタ内で使えるキーワードで、親クラスのメソッド、コンストラクタを呼び出すことができる。
`super()`も普通のメソッドと同じく引数を渡したり、オーバーロードもできる。

### abstractキーワード
前述の`Animal`クラスは<b>継承を前提としたクラス</b>だった。
このままであれば`Animal`クラスは継承をせずにインスタンスを生成し使うこともできるが、そのために作ったクラスじゃないっすよね。

そんなときは`abstract`キーワード。`abstract`はクラスとメソッドにも付けられる。

`abstract`は<b>抽象</b>、<b>無形</b>という意味なんですって。
その名の通り<b>抽象的なクラス、メソッド</b>なので、具体的にしてから使ってくれやってこと。

クラスに`abstract`を付けた場合は`new`キーワードによるインスタンス生成を禁止し、<b>継承をしないと使えないようになる。</b>
`abstract`を付けたクラスのことを<b>抽象クラス</b>なんて呼ぶ。

メソッドに`abstract`を付けた場合は処理を記述できず、<b>子クラスにオーバーライドを強制させる。</b>
子クラスからオーバーライドしないとコンパイルが通らなくなる。
また、当然のごとく`super()`は使えない。

```java:生き物
class abstract Animal{
  public void eat(String foodName){
    System.out.println(foodName+"食った");

    //消化処理
    syouka(foodName);
  }
  public void syouka(String foodName){
    System.out.println(foodName+"消化した");
  }

  public abstract void printName();
}
```

```java:おサルさん
class Monkey extends Animal{
  @Override
  public void eat(String foodName){
    //サルの食べ方をする処理が書かれていると思って

    //手で拾って...
    //おクチに...
    //運んで食べてほしい。

    //super()を使うと親クラスのeatメソッドを呼べる。
    super(foodName);
  }

  //printName()メソッドを必ずオーバーライドする必要がある。
  @Override
  public void printName(){
    System.out.println("ワイはおサルさんやで");
  }
}
```

### `final`キーワード
`final`を付けるとそれ以上に変更することを禁止できる。。

クラスに付けると継承を禁止する。
メソッドに付けるとオーバーライドを禁止する。
変数に付けると変数の宣言時以外の値の再代入を禁止する。

## 親クラス型として扱えるから
<b>親クラス型にアップキャストできる</b>のが本当に便利。

前述の動物たちをまた持ってくる。

```java:生き物
class Animal{
  public void eat(String foodName){
    System.out.println(foodName+"食った");

    //消化処理
    syouka(foodName);
  }
  public void syouka(String foodName){
    System.out.println(foodName+"消化した");
  }
}
```

```java:お犬さん
class Wanko extends Animal{
  @Override
  public void eat(String foodName){
    //犬の食べ方をする処理が書かれていると思って
    //エサ皿に...
    //Direct...
    //Attack!!（犬食い）

    //super()を使うと親クラスのeatメソッドを呼べる。
    super(foodName);
  }
}
```

```java:おサルさん
class Monkey extends Animal{
  @Override
  public void eat(String foodName){
    //サルの食べ方をする処理が書かれていると思って

    //手で拾って...
    //おクチに...
    //運んで食べてほしい。

    //super()を使うと親クラスのeatメソッドを呼べる。
    super(foodName);
  }
}
```

Animalとお犬さん、おサルさんは親子関係にある。
親子関係にあると<b>型変換ができるんですねぇ...！</b>

まず、型変換せずにつらつらと書いてみますか。

```java
class MeshiKue{
  public static void main(String[] args){
    Wanko dog = new Wanko();
    Monkey monkey = new Monkey();

    Gohan(dog);
    Gohan(monkey);
  }

  void Gohan(Wanko wanko){
    wanko.eat("りんご");
  }

  void Gohan(Monkey monkey){
    monkey.eat("りんご");
  }
}   
```

まぁ、こうなりますわな。
2種類だからいいけど、のちに仲間が増えてサーバルキャットとかアライさんとかフェネックやめるのだぁ～とかが増えたとしたら<b>`Gohan()`メソッドを種類の分だけいちいち書かなきゃいけなくなる</b>よね。

それが全部同じ処理だったら目もあてられないので、<b>型変換を使って1つで済むようにしよう。</b>

```java
class MeshiKue{
  public static void main(String[] args){
    Wanko dog = new Wanko();
    Monkey monkey = new Monkey();

    //お犬とおサルをAnimal型へアップキャストする
    Gohan((Animal)dog);
    Gohan((Animal)monkey);
  }

  //ひとつで済んだ！
  void Gohan(Animal animal){
    animal.eat("りんご");
  }
}   
```

子クラス型を親クラス型へキャストすることを<b>アップキャスト</b>、親クラス型を子クラス型へキャストすることを<b>ダウンキャスト</b>という。
ダウンキャストは1度アップキャストした変数にのみ行うことができる。

親子関係があると、親クラスに含まれているメソッド、変数を子クラスが必ず持っていることになるので、親クラスへキャストすることができる。

親子関係がない2のクラス間で同じ名前・仮引数のメソッドがあっても、<b>それはたまたま名前と仮引数がかぶったメソッドが存在しているだけ</b>に過ぎないので、静的型付け言語では型変換が行えない。

### ちなみに

Pythonとかの動的型付け言語だと<b>ダックタイピング</b>っつって、こういうたまたま同じ名前のメソッドがある親子関係のない状態でもこのような処理を行うことができる。
動的型付け言語は行き当たりばったりに一行ずつ実行していくので、その時に存在していればいいのだ。

# さいごに

<b>プログラム書くのメンドクセェェェェ！</b>って思ったらそれを解決できる言語機能がないか、より短い構文はないか探してみると、いいプログラマって呼ばれる人種に近づけると僕は信じてるので、頑張って探していこう！！