Java SE 11 Silver 学習 データ型／演算子／制御構造


## はじめに
- [Oracle Certified Java Programmer, Silver SE 11 認定資格](https://www.oracle.com/jp/education/certification/1z0-815-jpn-48261-ja.html)の受験にあたり、Java11について学習／検証した内容を資料としてまとめる。
- 本ドキュメントは、[出題範囲](https://www.oracle.com/jp/education/certification/1z0-815-jpn-48261-ja.html#skill)のうち、以下出題範囲に対応する調査を行った結果となる。
    - Javaの基本データ型と文字列の操作
    - 演算子と制御構造
    - 配列の操作

## 本ドキュメントで解説する内容
- データ型
    - プリミティブ型
    - 参照型
        - 配列
    - リテラル
        - 数値リテラル
        - 文字列リテラル
- 演算子
    - 演算の優先順位
    - インクリメント/デクリメント
- 制御構造
    - for
    - switch

## データ型
- Javaでは数値や文字が入った「プリミティブ型(基本データ型)」と、文字列、配列やクラスなどオブジェクトを参照する「参照型」のデータ型を扱う。

### プリミティブ型
|型|位置付け|ビット数|表現可能な範囲|初期値|ラッパークラス|
|:--|:--|:--|:--|:--|:--|
|boolean|真偽値|1|true または false|false|Boolean|
|char|Unicode文字|16|\u0000 ～ \uFFFF|¥u0000|Character|
|byte|符号付き整数|8|-128 ～ 127|0|Byte|
|short|符号付き整数|16|-32,768 ～ 32,767|0|Short|
|int|符号付き整数|32|-2,147,483,648 ～ 2,147,483,647|0|Integer|
|long|符号付き整数|64|-9,223,373,036,854,775,808 ～ 9,223,372,036,854,775,807|0L|Long|
|float|単精度浮動小数|32|±3.40282347E+38 ～ ±1.40239846E-45|0.0F|Float|
|double|倍精度浮動小数|64|±1.79769313486231570E+308 ～ ±4.94065645841246544E-324|0.0|Double|


**暗黙の型変換**
- プリミティブ型の代入時、小サイズデータ型の変数を大サイズデータ型の変数に(キャストなしに)代入できる。このことを暗黙の型変換と呼ぶ。
- 逆(大サイズデータ型の変数を小サイズデータ型の変数に代入)はコンパイルエラーとなる。
- ラッパークラス利用時は、暗黙の型変換は行われない。
- プリミティブ型配列は、Object型へのみ暗黙の型変換が可能。

```java
double d = 0.0;
int i = 0;
d = i; // OK(小データ型を大データ型に代入)
i = d; // コンパイルエラー(大データ型を小データ型に代入)

Double dd = 0.0;
Integer ii = 0;
dd = ii; //コンパイルエラー(ラッパークラス利用不可)

int[] ia = new int[3];
Object o = ia; // OK(Object型への変換)
```

|変換元＼変換先|boolean|char|byte|short|int|long|float|double|
|:--|:--|:--|:--|:--|:--|:--|:--|:--|
|boolean|-|X|X|X|X|X|X|X|
|char|X|-|X|X|O|O|O|O|
|byte|X|X|-|O|O|O|O|O|
|short|X|X|X|-|O|O|O|O|
|int|X|X|X|X|-|O|O|O|
|long|X|X|X|X|X|-|O|O|
|float|X|X|X|X|X|X|-|O|
|double|X|X|X|X|X|X|X|-|

### 参照型


**暗黙の型変換**
- 参照型においても以下のケースはキャストなしの型変換(暗黙の型変換)が可能となっている。
  - サブクラス配列 → スーパークラス配列
  - サブクラス → スーパークラス
  - サブクラス → インタフェース
  - サブインタフェース → スーパーインタフェース
  - 配列／クラス／インタフェース → Object型
    ```java
    Integer[] intArray = null;
    Object[] objectArray = intArray; // サブクラス配列 → スーパークラス配列
    Object object = intArray; // 配列 → Object
    
    Integer integer = null;
    Number number = integer; // サブクラス → スーパークラス
    Comparable comparable = integer; // クラス → インタフェース
    Object object2 = integer; // クラス → Object
    
    Path path = null;
    Iterable iterable = path; // サブインタフェース → スーパーインタフェース
    Object object3 = path; // インタフェース → Object
    ```


#### 配列
- 配列は複数の参照を一纏めにして取り扱うことが可能であり、配列型変数には配列インスタンスへの参照を代入できる。
- 配列は参照型となり、Object型のサブクラスとして定義される。

※＊TIPS**
- 配列型変数の宣言
  - 配列宣言時の大括弧`[]`は、データ型だけでなく変数名の後ろにも記述できる。以下のように分割して記述することも可能。
  ```java
    int[] a;
    int b[];
    int[][] c;
    int[] d[];
    int e[][];
  ```
- 初期化なしで配列インスタンスを生成すると、配列の各要素は以下の値で初期化される。
    - プリミティブ数値型(char, byte, short, int, long, float, double): 0
    - プリミティブ真偽値(boolean): false
    - オブジェクト(配列含む): null
- 配列の要素数を指定して配列インスタンスを生成できる。
    - 要1次元目の要素数は必ず指定する必要がある。
    - 全ての次元に要素数を指定する必要はないが、要素数を指定しない次元の下位次元の要素指定はできない。。
        ```java
            int[][][] a = new int[1][2][3]; // OK(1,2,3次元の配列インスタンスを生成)
            int[][][] b = new int[1][2][];  // OK(1,2次元の配列インスタンスのみ生成)
            int[][][] c = new int[1][][];   // OK(1次元目の配列インスタンスのみ生成)
            int[][][] d = new int[][][];    // コンパイルエラー(要素数の指定なし)
            int[][][] e = new int[][][1];   // コンパイルエラー(1次元目の要素数指定なし)
            int[][][] f = new int[][1][2];  // コンパイルエラー(1次元目の要素数指定なし)
            int[][][] g = new int[1][][2];  // コンパイルエラー(初期化されていない次元の下位次元の要素数が指定)
        ```
- 初期化子を利用すると、要素の初期化と配列インスタンスを生成を同時に実行できる。
    - 初期化子の内容が空白`{}`　の場合、配列の型宣言の全次元に要素数=0が指定されたものとして扱われる。
    - 要素数の指定と組み合わせることはできない。
        ```java
          int[] a = new int[]{1, 2, 3}; // OK(1次元配列インスタンスの生成)
          int[][] b = {{1,2}, {3,4}};   // OK(2次元配列インスタンスの生成)
          int[][] c = new int[][]{};    // OK(要素数0の2次元配列インスタンスの生成)
          int[][] d = {};               // OK(要素数0の2次元配列インスタンスの生成)
        ```
- 配列インスタンスが`clone`メソッドを実行すると、配列の内容がコピーされた新規インスタンスが生成される。
  ```java
    int[] n = {1, 2, 3};
    n.clone()[0]=10;
    System.out.println(Arrays.toString(n)); // 配列の内容がプリミティブ型のため、更新されない [1, 2, 3]

    int[][] n2 = {{1, 2, 3}};
    n2.clone()[0][0]=10;
    System.out.println(Arrays.toString(n2[0])); //配列の内容が配列(参照型)のため、更新される [10, 2, 3]
  ```
  - 配列インスタンス同士で`equals`メソッドを実行すると、`Object#equals()`が呼ばれるため、オブジェクト間の同一性が判定される。
  ```java
    int[] a1 = new int[]{1};
    int[] a2 = a1;
    a1.equals(a2) //true (オブジェクトが同一)

    int[] b = new int[]{1};
    a1.equals(b) //false (オブジェクトが異なる)
  ```


### リテラル
- ソースコード中で使用される、数値や文字列等を直接表現するデータのことをリテラルと呼ぶ。
- ソースコード内に、直接的にデータ型の値を記載する場合の記載する値を記載する値を指す。以下を指定できる。
  - 整数(int, short, byte, long)
  - 不動小数点(float, double)
  - 真偽値(boolean)
  - 文字(char)
  - 文字列(String)

|データ型|記法|例|
|:--|:--|:--|
|整数(int,short,byte)|整数リテラル|10|
|整数(long)|整数リテラル + `l` or `L`|10L||
|浮動小数点(float)|不動小数点リテラル + `f` or `F`|10.0F<BR>10.0f|
|浮動小数点(double)|不動小数点リテラル|10.0|
|真偽値(boolean)|`true` or `false`|true|
|文字(char)|シングルクォートで囲った単一文字|'A'|
|文字(char)|シングルクォート＋Unicode番号|'¥u0021'|
|文字(char)|0~65535までの数値|65|
|文字列(String)|ダブルクォートで囲った複数文字|”ABC"|

#### 数値リテラル
- 数値リテラルには小数点を含まない「整数リテラル」と小数点を含む「小数リテラル」が存在する。


**TIPS**
- 数値リテラルは、10進表現、16進表現、8進表現、2進表現で値を指定することが可能。
- 進数表現を識別する文字を数値リテラルの先頭に付与することで、10進数以外をリテラルに使用できる。
    - 16進数: 数値リテラルとして `0 ~ 9`の数値に加えて `a ~ f` 及び　`A ~ F`を指定できる。
    - 8進数: 数値リテラルとして `0 ~ 7`の数値のみ指定できる。
    - 2進数: 数値リテラルとして `0 ~ 1`の数値のみ指定できる。

|表現|記法|例|
|:--|:--|:--|
|10進数|数値リテラル|10|
|16進数|`0x` + 数値リテラル|0xA|
|8進数|`0` + 数値リテラル|012|
|2進数(Java7以降)|`0b` + 数値リテラル|0b1010|

- 不動小数点リテラルでは、小数表現に加えて指数表現で値を指定することが可能。
    - 10進数: 数値リテラルとして　小数点を含む`0 ~ 9`の数値に加えて、指数表現を指定できる。
    - 16進数: 数値リテラルとして 小数点を含む`0 ~ f/F`の数値に加えて、指数表現を指定できる。

|進数|記法|例|
|:--|:--|:--|
|10進数|数値リテラル + (`e` or `E`) + 指数`N`で、数値x10のN乗を表現|1.23e2 (=123)|
|16進数|数値リテラル + (`p` or `P`) + 指数`N`で、数値x2のN乗を表現|0x1.5p2 (=5.25)|

- 数値プリミティブ型の変数に数値リテラルを代入する場合、データ型が表現できる範囲の数値のみ指定可能。
    ```java
    int a = 10; //OK
    short b = 32767; //OK
    byte b = 255; //コンパイルエラー(データ型の範囲外)
    long c = 1.0; //コンパイルエラー(データ型の範囲外)
    ```
- 可読性向上を目的に区切り文字としてアンダーバー(_)を入力できる(Java7以降)。
  - リテラルの先頭と末尾には記述できない。
  - 記号の前後には記述できない。
  ```java
  int a = 123_456_789; // 123456789
  int b = 0_777; // 511
  ```

#### 文字列リテラル
  - 文字列リテラルは定数メモリ空間(コンスタントプール)に作成され、そこへの参照が変数に代入される。
  - 同一の文字列リテラルが複数回参照される場合、同一オブジェクトとして扱われる。
  - Stringインスタンスをnewで生成した場合、新しいString型オブジェクトが生成される。
  - `String#intern(String)`は、コンスタントプール上の参照を返却するため同一の文字列リテラルであれば同じオブジェクトとなる。
    ```java
    String a = new String("AAA");
    String b1 = "AAA";
    String b2 = "AAA";
    String c = a.intern();

    System.out.println(
        a.equals(b1) + ":" +  // true (同値性あり)
        a.equals(b2) + ":" +  // true (同値性あり)
        a.equals(c)  + ":" +  // true (同値性あり)
        b1.equals(b2) + ":" + // true (同値性あり)
        b1.equals(c) + ":" +  // true (同値性あり)
        b2.equals(c));        // true (同値性あり)
    
    System.out.println(
      String.valueOf(a == b1)  + ":" + // false (同値性なし)
      String.valueOf(a == b2)  + ":" + // false (同値性なし)
      String.valueOf(a == c)   + ":" + // false (同値性なし)
      String.valueOf(b1 == b2) + ":" + // true (同値性あり)
      String.valueOf(b1 == c)  + ":" + // true (同値性あり)
      String.valueOf(b2 == c));        // true (同値性あり)
    ```

## 演算子

### 演算の優先順位
- 利用する演算子によって、演算の優先度が決定される。
    - 優先順位
      - 上の行の演算子ほど優先順位が高い。
      - 同じ行の演算子の優先順位は同一。
    - 結合規則
      - 単項演算子、三項演算子、代入演算子は、右から左に評価される(右結合)
      - 上記以外の演算子は左から右に評価される(左結合)

|優先度|グループ|演算子|概要|例|結合|
|:----|:----|:----|:----|:----|:----|
|1|後置式|`++`<BR>`--`|後置インクリメント<BR>後置デクリメント|`expr++	`<BR>`expr--`|左|
|2|単項演算子|`++`<BR>`--`<BR>`+`<BR>`-`<BR>`~`<BR>`!`|前置インクリメント<BR>前置デクリメント<BR>正符号<BR>負符号<BR>ビット否定<BR>論理否定|`++expr`<BR>`--expr`<BR>`+expr`<BR>`-expr`<BR>`~b`<BR>`!b`|右|
|3|乗除演算子|`*`<BR>`/`<BR>`%`|乗算<BR>除算<BR>剰余|`m * n`<BR>`m / n`<BR>`	m % n`|左| |
|4|加減演算子|`+`<BR>`-`|加算<BR>減算|`m + n`<BR>`m - n`|左| |
|5|シフト演算子|`<<`<BR>`>>`<BR>`>>>`|sビット左にシフト<BR>sビット右にシフト(符号拡張)<BR>sビット右にシフト(ゼロ拡張)|`n << s`<BR>`n >> s`<BR>`n >>> s`|左|
|6|関係演算子|`<`<BR>`>`<BR>`<=`<BR>`>=`<BR>`instanceof`|より小さい<BR>より大きい<BR>以下<BR>以上<BR>型比較|`m < n`<BR>`m > n`<BR>`m <= n`<BR>`m >= n`<BR>`obj instanceof Class`|左| |
|7|等価演算子|`==`<BR>`!=`|等価<BR>不等価|`m == n`<BR>`m != n`|左|→[equals()との違い](type.html#compare_object)|
|8|ビット演算子(AND)|`&`|ビット単位の論理積|`m & n`|左|
|9|ビット演算子(XOR)|`^`|ビット単位の排他的論理積|`m ^ n`|左|
|10|ビット演算子(OR)|`\|`|ビット単位の論理和|`m \| n`|左|
|11|論理演算子(AND)|`&&`|条件の論理積|`expr1 && expr2`|左|
|12|論理演算子(OR)|`\|\|`|条件の論理和|`expr1 \|\| expr2`|左|
|13|三項演算子|`? :`|条件付き代入|`expr ? m : n`|右|
|14|代入演算子|`=`<BR>`+=`<BR>`-=`<BR>`*=`<BR>`/=`<BR>`%=`<BR>`&=`<BR>`^=`<BR>`\|=`<BR>`<<=`<BR>`>>=`<BR>`>>>=`|代入<BR>加算して代入<BR>減算して代入<BR>乗算して代入<BR>除算して代入<BR>乗除して代入<BR>ビットANDして代入<BR>ビットXORして代入<BR>ビットORして代入<BR>左シフトして代入<BR>右にシフトして代入(符号拡張)<BR>右にシフトして代入(ゼロ拡張)|`n = m`<BR>`n += m`<BR>`n -= m`<BR>`n *= m`<BR>`n /= m`<BR>`n %= m`<BR>`n &= m`<BR>`n ^= m`<BR>`n \|= m`<BR>`n <<= s`<BR>`n >>= s`<BR>`n >>>= s`|右|

出典: https://docs.oracle.com/javase/tutorial/java/nutsandbolts/operators.html

**TIPS**
  - プリミティブ型とラッパークラス間の演算は、暗黙的にラッパークラスがプリミティブ型にアンボクシングされる。
    ```java
    Integer a = Integer.valueOf(1);
    int b = 1;
    var c = a + b;
    System.out.println(c instanceof Integer);
    ```
    ```console:実行結果
    % java T1.java
    Main.java:12: エラー: 予期しない型
        System.out.println(c instanceof Integer);
                           ^
      期待値: 参照
      検出値:    int
    エラー1個
    エラー: コンパイルが失敗しました
    ```


  - 文字列同士は加算演算子で連結できる。
      - Stringオブジェクトがnullの場合、文字列`"null"`として連結される。
      - 数値+文字列の結果は、数値の文字列表現と文字列を連結した文字列となる。
      ```java
      String n = null
      System.out.println(1+2+n); // 3null
      System.out.println(n+1+2); // null12
      ```


### インクリメント／デクリメント
- 数値プリミティブ型およびそのラッパークラスに対して、インクリメント(1を加算)及びデクリメント(1を減算)できる。
    - 浮動小数点型においても実行できる。
    ```java
    int i = 0;
    System.out.println(++i); // 1
    Integer wi = Integer.valueOf(1);
    System.out.println(++wi); // 2

    double d = 2.0;
    System.out.println(++d); // 3.0
    Double wd = Double.valueOf(3.0);
    System.out.println(++wd); // 4.0
    ```
- 後置インクリメント
  - 後置 (`変数++`/`変数--`)： 変数の値を返却後、インクリメント／デクリメント処理を行う。
  ```java
  int c = 10;
  System.out.println(c++ + c); // 21　（10 + 11)
  ```
- 前置インクリメント
  - 前置 (`++変数`/`--変数`)： インクリメント／デクリメント処理を行ったのちに、変数の値を返却する。
  ```java
  int c = 10;
  System.out.println(++c + c); // 22(11 + 11)
  ```

### キャスト
- 参照型のオブジェクトを別の型のオブジェクトに変換すること。
    - 継承関係の無いクラスをキャストすると`ClassCastException`が発生する。
    - キャストなしで継承関係の無い変数を代入すると、コンパイルエラーが発生する。

- アップキャスト: 子クラスの型を親クラスの型へキャストすること。暗黙の型変換も利用可能。
    ```java
    Integer i = Integer.valueOf(1);
    Number n = (Integer)i;
    ```
- ダウンキャスト: 親クラスから子クラスに型を変換すること。明示的なキャストが必要。
    ```java
    Number n = Integer.valueOf(1);
    Integer i = (Integer)n;
    ```

## 制御構造

### for
- for文
   ```java
   for (初期化式; 条件式; 反復式) {
      処理部
   }
   ```
  - 初期化式
    - 初期化処理を定義できる。
      - 初期化処理では、for文の中でのみ利用可能な変数を定義できる。
      - コンマ区切りで同一の型の変数を複数定義可能。
      `int i = 0, j = 0`
    - 省略した場合は初期化式なしとなる。
  - 条件式
    - 条件に一致した場合のみ処理部が実行される。
    - 省略した場合は常に true として扱われる(無限ループ)
  - 反復式
    - 繰り返し処理が完了時に実行される処理。
    - コンマ区切りで複数処理を定義可能。
      `i++, j++`
    - 省略した場合は反復式なしとなる。
  
- 拡張for文
  - 配列やコレクションの全要素に対して、順番に処理を行う構文。
    ```java
    for (型 変数名: 配列あるいはjava.lang.Iterableのインスタンス){
    　処理部
    }
    ```

## switch
- 条件式に記載できる型
  - long以外の整数プリミティブ型(byte, short, int)
  - long以外の整数型(Byte, Short, Integer)
  - 列挙型(Enum)
  - 文字プリミティブ型(char)
  - 文字、文字列列(Character, String)
- case値に記載できるもの
  - 条件式の型と互換性のある型
  - 定数(final宣言された変数、またはリテラル)
  - nullでないこと

```java
switch (条件式){
  case 定数:
    // 式を評価した値が定数1と一致したときに実行される処理
    ...
    break;
}
```

**TIPS**
- defaultの記載順序は各caseの最後尾である必要はない。
    ```java
    switch(0) {
      default: 
        break;
      case 0:
        System.out.println("AAA"); // 実行される
        break;
    }
    ```

- 条件式に`null`が渡されると、例外`NullPointerException`が発生する。