【Java Silver🥈】プリミティブ型

Java Silver🥈の試験対策として、Javaのプリミティブ型についてまとめました。
- 🛑間違いやすい！　見直しポイント
- ⭐とりあえずこれだけでも！　重要ポイント
- 👁‍🗨着眼点・理由
- 📖用語

# リテラル
ソースコードに直接記載される値のこと

## 整数リテラル
ソースコードに直接記載される数値を表す数字

### 2・8・16進法表記
||2進法|8進法|10進法|16進法|
|:---:|:---:|:---:|:---:|:---:|
|先頭の文字|`0b`|`0`|(なし)|`0x`|
|例|`0b1010`|`0777`|`42`|`0xCAFE`|
- 🛑先頭に`0`をつけると8進法になる
	- `0999`などはコンパイルエラー
	- うっかり先頭を`0`でパディングしないように注意！

### 区切り文字"`_`"
- 整数リテラルは`_`で区切ることができる
``` java
// 使用例）Byteごとに区切って分かりやすくする
int mask = 0x00_00_FF_FF;
int hogeFlagBit = 0b00000000_00000000_00001000_00000000;
```
- ⭐`_`は記号の前後、先頭・末尾にはおけない
``` java
int a = _1234 // ✘
int b = 1234_ // ✘
int c = 0x_ABCD // ✘
```
- `_`は整数リテラルのみ有効
	- 🛑`Integer.parseInt`は`_`を受け付けない（NumberFormatException）

## ブール値リテラル
- ソースコードに直接記載されるブール値を表すキーワード
	- `true`, `false`のいずれか

## 文字リテラル
- ソースコードに直接記載される文字型を表す句
- ⭐シングルクォーテーション(`'`)で文字を囲う
	- `'0'`, `'A'`, など
- 🛑文字リテラルは整数型に代入可能
	- `byte`にも代入可能

# プリミティブ型のサイズと大きさ
- プリミティブ型はそれぞれで扱える値の範囲とメモリサイズのbit数が決まっている

|型|bit数|最小値|最大値|
|:---:|:---:|:---:|:---:|
|`byte`|8|⭐$-2^7 = -128$|⭐$2^7-1 = 127$|
|`short`|16|⭐$-2^{15} = -32768$|⭐$2^{15}-1 = 32767$|
|`int`|32|$-2^{31} = 2147483648$|$2^{31}-1 = 2147483647$|
|`long`|64|$-2^{63}$|$2^{63}-1$|
|`char`|🛑16|$0$|$2^{16}-1$|
|`float`|32|$-(2 - 2^{-23} \cdot 2^{127})$|$2 - 2^{-23} \cdot 2^{127}$|
|`double`|64|$-(2 - 2^{-52} \cdot 2^{1023})$|$2 - 2^{-52} \cdot 2^{1023}$|

- 👁‍🗨浮動小数 (float, double) は符号・指数部・仮数部に分かれている
    - 仮数部と2の指数乗の積が値になる
    - 符号部で値の正負を決める

|名称|float|double|
|:---:|:---:|:---:|
|__符号部__|1bit|1bit|
|__指数部__|8bit|23bit|
|__仮数部__|11bit|52bit|

- 仮数部の長さによって浮動小数点の値の精度が決まる
- 整数を浮動小数で表現すると精度が落ちる

# プリミティブ型の拡大変換
- ⭐プリミティブ型の変数を使用するとき、値域が小さい型から大きい型へと自動で変換してくれる機能
- 変換は値を使用するとき（以下の場合）に行われる
	- 代入するとき
	- メソッドの引数として渡すとき
	- 演算するとき
- 拡大変換は扱える値の範囲が狭い型から広い型へと変換する場合にのみ行われる
    - `short`➡`long`や`int`➡`double`の変換は拡大変換になる
    - 🛑`long`➡`float`はbit数が64bitから32bitと減少するが拡大変換される
    - 🛑`short`➡`char`はbit数が同じだが互いに拡大変換されない
- ⭐拡大変換できない場合は<B>キャストによる明示的な変換</B>が必要
``` java
double d = 1.23d;
int i = (int) d; // キャストによる明示的な変換
```

<details><summary><B>👁‍🗨拡大変換の対応表</B></summary>
（✔：対応している　✘：対応していない（要キャスト））

|変換元＼変換先|`char`|`byte`|`short`|`int`|`long`|`float`|`double`|
|:---:|:---:|:---:|:---:|:---:|:---:|:---:|:---:|
|`char`|-|✘|🛑✘|✔|✔|✔|✔|
|`byte`|✘|-|✔|✔|✔|✔|✔|
|`short`|🛑✘|✘|-|✔|✔|✔|✔|
|`int`|✘|✘|✘|-|✔|✔|✔|
|`long`|✘|✘|✘|✘|-|🛑✔|✔|
|`float`|✘|✘|✘|✘|✘|-|✔|
|`double`|✘|✘|✘|✘|✘|✘|-|
</details>

# ラッパークラス
- ラッパークラス：プリミティブ型をオブジェクト化し、参照型で扱えるようにしたもの
- オートボクシング：プリミティブ型⇔ラッパーの相互の自動変換機能
	- ラッパークラスのインスタンスをあたかもプリミティブ型であるかのように使える
- `char`型のラッパークラスは`Character`
    - 🛑`Char`型は存在しない

|プリミティブ型|ラッパ型|ボクシング|アンボクシング|文字列から変換|
|:---:|:---:|:---:|:---:|:---:|
| byte | java.lang.Byte | `valueOf(byte)` | `byteValue()` | `parseByte(String)` |
| short | java.lang.Short | `valueOf(short)` | `shortValue()` | `parseShort(String)` |
| int | java.lang.Integer | `valueOf(int)` | `intValue()` | `parseInt(String)` |
| long | java.lang.Long | `valueOf(long)` | `longValue()` | `parseLong(String)` |
| float | java.lang.Float | `valueOf(float)` | `floatValue()` | `parseFloat(String)` |
| double | java.lang.Double | `valueOf(double)` | `doubleValue()` | `parseDouble(String)` |
| boolean | java.lang.Boolean | `valueOf(boolean)` | `booleanValue()` | `parseBoolean(String)` |
| char | 🛑java.lang.Character | `valueOf(char)` | 🛑`charValue()` | 🛑 (なし[^1]) |

[^1]: `String`クラスの`toCharArray`メソッドや`charAt`メソッドでchar型に変換できる

### オートボクシング
- ラッパークラスのインスタンスは、プリミティブ型と演算するとき自動的にプリミティブ型に変換される
``` java
void test(){
	Integer integer = Integer().intValue(123);
	int i = integer.intValue();
	
	// プリミティブ型とラッパクラス型の論理演算
	// Integer型がint型に自動変換される
	boolean b = (i == integer);
}
```

### `var`型
- 変数の型を指定しなくても自動で推定してくれる機能
- ⭐`var`はローカル変数専用
- ⭐`var`の初期化は必須
	- 🛑`var`は`null`では初期化できない（型を推定できないため）
``` java
class Test {
    // ✘varはフィールドでは使えない（コンパイルエラーになる）
    var variable;

    void test() {
        // ✓右辺がint型なのでvarはint型と推定される
        var varIntegerA = 0;

        // ✘varは宣言時に初期化もしないといけない（コンパイルエラーになる）
        var varIntegerB;
        varIntegerB = 1;

        // ✓varで拡張for文の変数の型を推定させることもできる
        java.util.List<String> list = Arrays.asList("A", "B", "C");
        for (var str : list) { // listの要素はString型なのでvarはString型と推定される
            System.out.println(str);
        }
    }
}
```

# 演算子
- __演算子__：計算を意味する記号
    - __単項演算子__：`++`など、１つの値を取る演算子
        - `-123`のような負数を表す`-`は単項演算子
    - __二項演算子__：`+`, `*`など、２つの値を取る演算子
    - __三項演算子__：`?`など、３つの値を取る演算子
- __オペランド__：演算子で計算する対象の値
    - `1+2`なら`1`と`2`がオペランド

## 演算子の結合の強さ
- 演算子には結合の強さが決められている
    - 算数でいえば式で出てくる順番にかかわらず、＋より×を先に計算するのと同じ考え方
    - プログラムは演算子の結合が強い方から順に計算される
- 重要な結合の強さを覚えておこう（`()`内の式が先に計算される）
    - `1 + 2 * 3` ➡ `1 + (2 * 3)`
    - `a || b && c` ➡ `a || (b && c)`
    - `!a && b` ➡ `(!a) && b`
    - `1 + ++i` ➡ `1 + (++i)`
        - `i = 1`なら計算結果は`3`
    - 🛑`(int) 1.2 + 3.4` ➡ `((int) 1.2) + 3.4`
        - 小数の計算結果を整数に変えたいときは`(int) (1.2 + 3.4)`とする
    - 🛑`flag ? 3 : 1 * n` ➡ `flag ? 3 : (1 * n)`
        - `n`の値を`flag`が`true`のときだけ`3`倍にしたいときは`(flag ? 3 : 1) * n`とする


<details><summary>演算子の結合強さ表</summary>

- 表の上の方に行くほど結合が強くなる
- 演算子の記号
    - `T`:型
    - `I`:識別子
    - `X`:値(オブジェクト含む)
    - `N`:数値
    - `B`:論理値

|演算子|内容|
|:---:|:---:|
|`I()` `I[]` `I.I` `new T` `N++` `N--`|`func("A")` `array[0]` `obj.value` `new String("ABC")` `i++` `i--`|
|`!B` `~N` `+N` `-N` `++N` `--N`|`!isFoo` `~mask` `+12.3` `-273.15` `++i` `--i`|
|`(T)`|`(int) 12.3`|
|`N*N` `N/N` `N%N`|`2*3`|
|`N+N` `N-N`|`1+1`|
|`N<<N` `N>>N` `N>>>N`|シフト演算|
|`N>N` `N>=N` `N<N` `N<=N` `instanceof`|論理比較|
|`X==X` `X!=X`|`X == 42`|
|`X&X`|ビット演算のAND|
|`X^X`|ビット演算のXOR|
|`X\X`|ビット演算のOR|
|`B&&B`|論理演算のAND|
|`B\|\|B`|論理演算のOR|
|`B?X:X`| `(x >= 0)? x : -x` |
|`I=X` `I+=N` `I-=N` `I*=N` `I/=N` `I%=N` `I<<=N` `I>>=N` `I>>>=N` `I&=N` `I\|=N` `I^=N`|演算と代入|

</details>


## インクリメント演算子
- `++`・`--`の演算子で整数型の変数の値を1増やす・1減らすことができる
	- メモリを読む、値を増やす、メモリに書き込む（副作用）という３つの動作がある点に注意
- `++`を変数につける場所で動作が変わる
	- 左に着けると評価 → インクリメントの順に処理される
	- 右につけるとインクリメント → 評価の順に処理される
``` java
int a = 0;
System.out.println(a++); // "0"
System.out.println(a); // "1"

int b = 0;
System.out.println(++b); // "1"
System.out.println(b); // "1"
```
- 演算は基本的に左から実行される
    - `n + n++ + --n`は`((n + n++) + --n)`と考える。
``` java
int n = 10;
int a = n + n++ + --n; // 30になる
```
- 🛑`*`、`/`と`%`の優先度は同じ

## 🛑String連結演算子 `+`
- `String`クラスは特別に`+`演算子が用意されている
- ふたつの文字列をひとつの文字列に連結して返す
    - オペランドの片方が`String`型なら`String`の`+`演算子の扱いになる
    - `String`以外のオペランドは`toString`で文字列化される
        - 🛑`0 + "1"`は`"01"`になる（左側が`String`以外でも変換される）
- ⭐値の`+`演算子と混ざっているときは特に注意！
``` java
// 2つの+演算子が混ざっている例
// (3 + 4).concat("7").concat("5").concat("2");
System.out.println(3 + 4 + "7" + 5 + 2); // 7752
```

---
2023/08/05 拡大変換の内容を追記・修正（PECMMさん、指摘ありがとうございます！）
2023/10/08 演算子の表の誤りを修正（PECMMさん、指摘ありがとうございます！）、表があるとそれを全部覚えないといけないのかという感じがするので折り畳み表示に変更し重要点だけ文章に抜出、その他字句修正