Hello Worldからの復習 ～参照型の型変換編～

##### お品書き
+ 参照型の型変換って？
+ キャストするパターン
+ 型変換Sample

----


以前復習した基本データ型の型変換↓

https://qiita.com/tianshandafu894/items/37e47f1654718725b9d6

基本データ型はint型とかdouble型のように数値を扱えるようにまとめられている。
その**データ型間**で**型の変換**ができるという話。

◆参照型の型変換って？
-
参照型の型変換ができるときというのは、

:::note
型変換する前のクラスと変更後のクラスの間で継承関係にあるとき
:::

継承関係にあるクラス同士でオブジェクトの型変換↓

:::note
スーパー = サブ のときは**自動**
サブ = スーパーのときは**キャストで明示**
:::

イメージ図
-

```mermaid
classDiagram
    direction RL
    Person <|--"継承"Student
    class Person{
    name
    Preson(...)
    display()
    }
    class Student{
    stuNo
    Student(..)
    display()
    chgStuNo(...)
    }

```
1,Stidentクラスでdisplayメソッドをオーバーライドしている。
2，サブクラス独自のメソッドとしてchgStuNoメソッドを持っている

**上記を踏まえてSample**

```java:例
Student stu1 = new Student(..); //オブジェクトの生成
Person psn = stu1; //インスタンスのアドレス値が代入される
Student stu2 = (Student)psn; //右辺でキャストして型変換

```

```mermaid
stateDiagram-v2
    stu1 --> Student
    psn -->Person
    state Student {
    stuNo
    Student(...)
    display(.)
    chgStuNo(...)
        state Person {
            name
            Person()
            display()
        }
    }
```
stu1領域はStudentのインスタンスの領域を指し示す変数
psn領域はstu1の値(アドレス値)をコピーする。
同じインスタンスを指し示す。
psnはPersonクラスの変数のため、見れる領域はPersonの情報のみとなる。

stu1はStudentの情報をすべて扱えるが、psnはPersonクラスの変数のため、Personクラスの情報のみ

指し示す場所が微妙に違うのを注意。

そのため、StudentクラスからPersonクラスは自動で型変換が可能。

キャストするパターン
-

```mermaid
stateDiagram-v2
    stu1 --> Student
    psn -->Person
    stu2 --> Student
    state Student {
    stuNo
    Student(...)
    display(.)
    chgStuNo(...)
        state Person {
            name
            Person()
            display()
        }
    }
```

psnの値がstu2にコピーされる

一般的にはPersonクラスの変数からStudentクラスの変数に変換したときにメモリ上に情報があるとは限らない。
そのため、PersonクラスからStudentクラスに型変換しようとするときにエラーを出す。
変換しても問題ないことをコンパイラーに教えるために、キャストして教える。

```java:例
Student stu1 = new Student(..); //オブジェクトの生成
Person psn = stu1; //インスタンスのアドレス値が代入される
Student stu2 = (Student)psn; //右辺でキャストして型変換
psn.display(); //➡オーバーライド有効
psn.chgStuNo(...); //➡コンパイルエラー
stu2.chgStuNo(...); //➡OK
```

:::note
サブクラスの変数をスーパークラスの変数に代入は自動
※サブクラスの中には必ずスーパークラスの情報があるため。
スーパークラスの情報をサブクラスの変数に代入するときはインスタンスの中から外を見に行くことになるので、メモリ上に欲しい情報があるとは限らない。
メモリ上にはサブクラスの情報があるのをコンパイラに知らせるために明示的にキャストする必要がある。
:::


◆型変換Sample
-
```java:java
public class Person5{
  private String name;

  public Person5(String name){
    this.name = name;
  }
  public void display(){
    System.out.println("名前：" + name);
  }
}
```

```java:java
public class Student5 extends Person5{
  private int stuNo;

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

```java:java
public class StuSample5{
  public static void main(String[] args){
    Student5 stu1 = new Student5("大輔",1);
    Person5 psn = stu1;
    psn.display();
    // psn.chgStuNo(1001);　コンパイルエラー

    /* 補足：instanceofキーワード
       オブジェクトのクラスを特定する
       対象オブジェクト instanceof クラス名 */
    if(psn instanceof Student5){ //Student5クラスのインスタンスかどうか？trueかfalse
      Student5 stu2 = (Student5)psn;
      stu2.chgStuNo(1001);
      stu2.display();
    }
  }
}
```

```cmd:cmd
C:\Java\1>java StuSample5
名前：大輔
学籍番号：1
名前：大輔
学籍番号：1001
```

ちなみに、psnからメソッドを呼び出し、キャストをつけないとどうなるか。

```java:java
public class StuSample5{
  public static void main(String[] args){
    Student5 stu1 = new Student5("菅原",1);
    Person5 psn = stu1;
    psn.display();
    psn.chgStuNo(1001); //psnからメソッドを呼ぶとコンパイルエラー

  
    if(psn instanceof Student5){
    // Student5 stu2 = (Student5)psn;
      Student5 stu2 = psn; 
      //キャスト演算子をつけないとどうなるか
      stu2.chgStuNo(1001);
      stu2.display();
    }
  }
}
```

```cmd:cmd
C:\Java\1>javac StuSample5.java
StuSample5.java:6: エラー: シンボルを見つけられません
    psn.chgStuNo(1001);
       ^
  シンボル:   メソッド chgStuNo(int)
  場所: タイプPerson5の変数 psn
StuSample5.java:12: エラー: 不適合な型: Person5をStudent5に変換できません:
      Student5 stu2 = psn;
                      ^
エラー2個
```