Java　継承１：オーバーライド、thisとsuper

## 継承とは
既存のクラスを元に変数やメソッドなどの新しい処理や機能を追加したクラスを作る事。
継承関係にある親のクラス（既存のクラス）を**スーパークラス**、子のクラス（既存のクラスを元に変数やメソッドを追加したクラス）を**サブクラス**と呼ぶ。
![スクリーンショット 2022-11-06 10.55.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2785154/6834ef52-50b0-5a1a-f213-19b57e41e8cf.png)
上の写真ではPersonクラスがスーパークラス、SutudentとTeacherクラスがサブクラスになる。

Personクラスでは名前などを扱う変数やメソッドを定義しているとする（斜線の部分が変数やメソッドのイメージ）。Personクラスから継承を行うことでサブクラスであるSutudentとTeacherクラスでPersonクラスが持っている変数やメソッドが使える様になり、さらにSutudentとTeacherクラス独自の変数やメソッドを追加したりする事が出来るようになる。

継承するにはextendsというキーワードを使う。
```:継承の記述
class サブクラス　　extends スーパークラス{
       :
}

　　　//例文
class Student　　extends Person{
       :
}

```
継承をすることでコーティング、メンテナンスが楽になる。
継承できるクラスは一つだけ（extendsキーワードの後に書けるスーパークラスは一つだけ）。
コンストラクタは継承しない（コンストラクタの名前はクラス名と合わせるから）（superキーワードを用いることでサブクラスでスーパークラス内のコンストラクタを呼び出して利用する方法がある）。
### 例文１
```:実行用のクラス
public class StuSample{
  public static void main(String[] args){
    Student stu = new Student();

    //スーパークラスのメソッド
    stu.setName("菅原");    
    stu.display();

    //サブクラスのメソッド
    stu.setStuNo(1);
    stu.displayStuNo();
  }
}
```
```:スーパークラス
public class Person{
  private String name;

  public void setName(String n){
    name = n;
  }
  public void display(){
    System.out.println("名前:" + name);
  }
}
```
```:サブクラス
public class Student extends Person{
  private int stuNo;

  public void setStuNo(int s){
    stuNo = s;
  }
  public void displayStuNo(){
    System.out.println("学席番号:" + stuNo);
  }
}
```
```:出力結果
名前:菅原
学席番号:1
```
実行用クラスの３行目でサブクラスであるStudentクラスのオブジェクトstuを作っている。
StudentクラスはPersonクラスから変数やメソッドを継承しているので６、７行目の様にPersonクラスの変数とメソッドが使える。


## オーバーライドとは
サブクラスでスーパークラスのメソッドを再定義（メソッドを上書き）する事。
オーバーライドするには**戻り値の型**、**メソッド名**、**引数の型と数**を全て同じにしないといけない。
＊似たような名前のオーバーロードがあるがオーバーロードは一つのクラスの中でメソッドを複数定義する事。

### 例文２
```:実行用クラス
public class StuSample2{
  public static void main(String[] args){
    Student2 stu = new Student2();
    stu.setName("菅原");    
    stu.setStuNo(1);
    stu.display();
  }
}
```
```:スーパークラス
public class Person2{
  private String name;

  public void setName(String n){
    name = n;
  }
  public String getName(){
    return name;
  }
  public void display(){
    System.out.println("名前：" + name);
  }
}
```
```:サブクラス
public class Student2 extends Person2{
  private int stuNo;

  public void setStuNo(int s){
    stuNo = s;
  }
  public void display(){
    System.out.println("名前：" + getName());
    System.out.println("学籍番号：" + stuNo);
  }
}
```
```:出力結果
名前：菅原
学籍番号：1
```
スーパークラスとサブクラスの両方にdisplayメソッドがあるがオーバーライド（上書き）されているのでサブクラスのdisplayメソッドが表示される。

## superでスーパークラスのメソッドを呼び出す
superキーワードを使うと、スーパークラスの変数、メソッドをサブクラスから実行できる。
superを使うことで同じコードを書かなくて済むようになる。
super の後ろにドット(.)をつけて記述する。
```
super.メソッド名(引数)
```

## superとthisの書き分けや使いどころ
this は「自分自身」、super は「親」を指す。
thisとsuper はそれぞれが持つフィールドやメソッド、コンストラクタへアクセスするために「自分自身」なのか「親」なのかを特定する方法として使われる。
```
this.~ = 自分のクラスのオブジェクトの変数、メソッドの呼び出し
super.~ = スーパークラスの変数、メソッドの呼び出し
```

```:例文
// 実行用クラス
class Main {
  public static void main(String[] args) {
	  Student stu = new Student();
	    stu.name = "田仲";
	    stu.stuNo = 12;
	    stu.display();
	
  }
}
  //スーパークラス
class Person{
  String name;

  void setName(String name){
  this.name = name;
  // 右辺が引数のname、左辺が変数のname　
 }
  void display(){
	  System.out.println(this.name);
 }
}

 //サブクラス
class Student extends Person{
  int stuNo;

  void display(){
  super.display();
      System.out.println(stuNo);
 }
}
```
```:出力結果
田仲
12
```
**thisキーワード**
スーパークラス内にnameという同じ名前で変数と引数が定義されてしまっているの区別がつかなくなってしまうがthisキーワードをつける事で区別をつける事が出来る。
```
this.name = name;
　　　// 右辺が引数のname、左辺が変数のname　
```
この様にthisキーワードをつける事をつける事で引数の名前を変数の名前と合わせる書き方が出来、引数の名前をわざわざ考えなくて済む。

**superキーワード**
スーパークラスに書かれたdisplayメソッドをサブクラスでオーバーライドしている。
```
void display(){
  super.display();
      System.out.println(stuNo);
 }
```
super.display();と記述することでスーパークラスのdisplayメソッドを（上書きされていないdisplayメソッドを）呼び出している。
この様にsuperキーワードを用いて書くことでサブクラスで新しく変数nameを出力するメソッドを書かなくて良くなり、修正したい場合はスーパークラスのdisplayメソッドを修正するだけで済む。

## superとthisによるコンストラクタの呼び出し
コンストラクタは継承されないがsuper、thisの後ろに（）を書くことでコンストラクタを呼び出すことが出来る。
クラスの中にいくつかコンストラクタを書きたい、そのコンストラクタの中で似たような処理をさせたい時に使い、同じ処理を何回も書かなくて済むようになる。
```
this(引数) ←同じクラスの中でコンストラクタを呼び出せる
super(引数)　←スーパークラスの中でコンストラクタを呼び出せる
```
```:例文
// スーパークラス
class Person{
  String name;
  Person(){
    this("未設定");
  }
  Person(String name){
    this.name = name;
  }
}

// サブクラス
class Student extends Person{
  int stuNo;
     :
  Student(String name, int stuNo){
    super(name);
    this.stuNo = stuNo;
  }
}
```
**thisによるコンストラクタの呼び出し**
スーパークラス内で引数なしのコンストラクタPersonと引数ありのコンストラクタPersonが定義されている。
引数なし側のコンストラクタPerson内でthis("未設定");と記述することで引数あり側のコンストラクタPersonを呼び出し、"未設定"という文字列がthis.nameに代入される。

**superによるコンストラクタの呼び出し**
サブクラス内では引数を二つ持ったコンストラクタStudentが定義されている。
super(name);と記述する事でスーパークラスの引数nameを一つ持ったコンストラクタが呼び出されて(スーパークラスに記述されたPerson(String name)が呼び出される)文字列が代入される。
this.stuNo = stuNo;でサブクラス内（自分のクラス内）の数字が代入される。


✳︎**this()、super()を記述する際はコンストラクタ内の先頭に記述する。** （なければ自動的にsuper()；が挿入される。）　

## 例文３
```:実行用クラス
public class StuSample3{
  public static void main(String[] args){
    Student3 stu = new Student3("菅原");
    stu.display();
  }
}
```
```:スーパークラス
public class Person3{
  private String name;

  public Person3(String name){
    this.name = name;
  }
  public void display(){
    System.out.println("名前：" + name);
  }
}
```
```:サブクラス
public class Student3 extends Person3{
  private int stuNo;

  public Student3(String name){
    this(name, 999);
  }
  public Student3(String name, int stuNo){
    super(name);
    this.stuNo = stuNo;
  }
  public void display(){
    super.display();
    System.out.println("学籍番号" + stuNo);
  }
}
```

## 参考記事
https://www.youtube.com/watch?v=DkzlNYCVkZ8&t=365s

https://www.youtube.com/watch?v=_K3icVzjz-s