Java入門シリーズ(型変換)

## はじめに

こんにちは。
この記事は「これからJavaを始める方」や「久々にJavaにやる方」向けに型変換についてのまとめ記事です。

変数とは何かといったプログラミング自体についての説明は行わないので、プログラミング初心者の方には向いてない記事かもしれません。

Javaの変数の宣言方法や型についての説明は[前章](https://qiita.com/aoyaman/items/3922c25589dc6084451a)を参照ください。

Java入門シリーズとして下記の記事を準備中です。

- [変数と型](https://qiita.com/aoyaman/items/3922c25589dc6084451a)
- 型変換　←いまここ
- 変数のスコープ（準備中）
- 文字列の操作（準備中）
- 配列の操作（準備中）
- 演算子（準備中）
- 条件分岐（準備中）
- 繰り返し処理（準備中）
- クラスについて（準備中）
- 抽象クラス（準備中）
- インターフェース（準備中）
- カプセル化（準備中）
- モジュールについて（準備中）

## 型変換とは

変数を宣言する際に型を指定する必要がありますが、
その変数の値を別の型に変換したケースが色々とあります。

int型を変数を四則演算した際に、
long型に変換したい場合やdouble型に変換したい場合があったり、

画面に表示するために数値型を文字列形とくっつけたい場合があったり
など色々とあります。

用語としては、型変換することをキャストするとも言います。

型変換(キャスト)を明示する方法は型の名前を()で囲むことです。

```Java
int a = 5;
double b = (int)a;
```

そのほかに四則演算を行った際に昇格という型変換が行われたりします。
（後述参照）


## 基本型(プリミティブ型)の変換

byte型からint型やlong型への変換や
int型からlong型への変換など

小さいサイズから大きいサイズへの変換時は**値は失われない**です。

```java
class Main {
  public static void main(String[] args) {
    byte a = 127;
    byte b = -128;
    int c = (int)a;
    int d = (int)b;
    System.out.println(c); // -> 「127」と出力される
    System.out.println(d); // -> 「-128」と出力される

    int e = 2147483647;
    int f = -2147483648;
    long g = (long)e;
    long h = (long)f;
    System.out.println(g); // -> 「2147483647」と出力される
    System.out.println(h); // -> 「-2147483648」と出力される
  }
}
```

逆に大きいサイズから小さいサイズへの変換時は**値は失われる**ことになります。

どのように失われるかと言うと、ビット単位で上位のビット達が失われます。
下記の例ではわかりやすく１６進数で表現します。

```Java
class Main {
  public static void main(String[] args) {
    int a = 0x12345;
    byte b = (byte)a;
    short c = (short)a;
    System.out.printf("0x%05x\n", a); // -> 「0x12345」と出力される
    System.out.printf("0x%05x\n", b); // -> 「0x00045」と出力される
    System.out.printf("0x%05x\n", c); // -> 「0x02345」と出力される
  }
}
```

floatやdoubleなどの小数点型とintやlongなどの整数型の型変換については
結構ややこしいのでこの記事(入門レベル)では割愛します。

## 参照型(クラス型)の変換

AというクラスがBというクラスを継承しているとき、
AからBへの変換、BからAへの変換ができる。

```Java
public class OyaClass {
  public void print() {
    System.out.println("I am OyaClass! ");
  }
}

public class ChildClass extends OyaClass {
  private String moji;
  public ChildClass(String moji) {
    this.moji = moji;
  }
  public void print() {
    System.out.println("I am ChildClass! " + moji);
  }
}

class Main {
  public static void main(String[] args) {
    ChildClass cc = new ChildClass("Yes! Yes!");
    cc.print(); // -> 「I am ChildClass! Yes! Yes!」と出力される

    OyaClass oc = cc;
    oc.print(); // -> 「I am ChildClass! Yes! Yes!」と出力される

    ChildClass cc2 = (ChildClass)oc;
    cc2.print(); // -> 「I am ChildClass! Yes! Yes!」と出力される

    OyaClass oc2 = new OyaClass();
    oc2.print(); // -> 「I am OyaClass! 」と出力される

    ChildClass cc3 = (ChildClass)oc2; // -> 例外が発生する。
    cc3.print();
  }
}
```
上述のように変数の型を変更しても実体(インスタンス)はnewで生成したものになります。
最後の親クラスとして生成した実体を子クラスに型変換しようとすると
例外が発生します。

```
Exception in thread "main" java.lang.ClassCastException:
class OyaClass cannot be cast to class ChildClass
(OyaClass and ChildClass are in unnamed module of loader 'app')
 at Main.main(Main.java:15)
```

参照型(クラス型)の型変換はこの章ではこれ以上は割愛します。
「抽象クラス」や「インターフェース」の章にてもう少し詳細な内容を記載予定です。

## 文字列への変換

nullも含めて全ての型から文字列(String)型へ変換できます。
文字列と+演算子でつなげることで文字列に変換されます。

```Java
class Main {
  public static void main(String[] args) {
    int a = -100;
    double b = 123.456;
    Integer c = null;
    int d = 100;

    String sa = "" + a;
    String sb = "" + b;
    String sc = "" + c;
    String sad = "" + a + d;
    String sad2 = "" + (a + d);
    System.out.println(sa);   // -> 「-100」と出力される
    System.out.println(sb);   // -> 「123.456」と出力される
    System.out.println(sc);   // -> 「null」と出力される
    System.out.println(sad);  // -> 「-100100」と出力される
    System.out.println(sad2); // -> 「0」と出力される
  }
}
```

## エラーになる変換

- 基本型から参照型への変換(文字列変換を除く)
- 参照型から基本型への変換

などの変換はエラーになります。
![キャストコンパイルエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/af5e2fa4-bca1-8b71-ce3c-f3e3b91cd1f0.png)


## 昇格(プロモーション)
byte, short, charなどの型の変数を四則演算（加減乗除）した場合には
int型に変換されてから四則演算（加減乗除）されます。

この「int型に変換されてから」のことを昇格(プロモーション)と言います。

下記のように、
int型とbyte型の変数を掛け算したときだけでなく、
byte型とbyte型の変数を掛け算した時もint型に変換されています。
byte型は-128〜127しか値を入れれないですが、それを超えた値が出力されてますね。

```Java
class Main {
  public static void main(String[] args) {
    int a = 40;
    byte b = 30;
    byte c = 20;

    System.out.println(b*a); // -> 「1200」と出力される
    System.out.println(b*c); // -> 「600」と出力される
  }
}
```

では、上記のプログラムの最後に下記のような１行追加してみるとどうなるでしょうか？

```Java
class Main {
  public static void main(String[] args) {
    int a = 40;
    byte b = 30;
    byte c = 20;

    System.out.println(b*a); // -> 「1200」と出力される
    System.out.println(b*c); // -> 「600」と出力される
    byte d = b * c;
  }
}
```

すると、コンパイルエラーになります。
「b * c」がint型に変換されてる証拠ですね。
![昇格のコンパイルエラー.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/150699/2cb474d0-f79f-9348-22ee-407cca344563.png)

## おわりに

以上が型変換についての説明となりますが、いかがでしたでしょうか？

おそらく、Javaを勉強始めたばかりの方は「へぇ〜」となるだけだとは思いますが、
Javaのプログラミングを進めていると必ず型変換に出会うと思いますので、
その際に思い出して頂けると幸いです。

おわり。