Java Silver SE 11 対策・ポイントメモ

Java Silver SE 11を現在勉強中のものです。
最近やっと模擬問題で合格点を取れるレベルまでになれたので、これまでのポイントをまとめていこうと思います。

# 基本データ型と文字列操作
## プリミティブ型の型変換について

### ■プリミティブ型の大小関係

double  >  long  >  float  >  int  > short  >  byte

の順番。

### ■小リテラルを大型の変数へ代入　=　暗黙的に変換。
小さい型のリテラルを大きい型の変数に代入すると、暗黙的に変換され代入することができる。
これは、接尾辞がついていても暗黙的変換は適応される。

```java
double d = 3.0;

long l = 2;

d = l;

System.out.println(d); // 2.0が出力。

```
### ■大リテラルを小型の変数へ代入　=　明示的なキャストが必要。
大きい型のリテラルを小さい型の変数に代入する場合、明示的なキャストを行わないとコンパイルエラーになる。
```java
double d = 3.0d;

float f = d; // コンパイルエラー。

float f2 = (float)d;

System.out.println(f2); // 3.0が出力。

float f3 = 3.0; // javaの浮動小数点のデフォルトはdouble型なので、コンパイルエラー。

```
### ■文字　⇄　数値の変換は必ずキャストが必要。
```java
char c = 89;
System.out.println(c);  // Yが出力。

byte b = 89;
char c = b;            // コンパイルエラー。
System.out.println(c);

byte b = 89;
char c = (char)b; 
System.out.println(c); // Yが出力。

char c = 89;
byte b = (byte)c; 
System.out.println(b); // 89が出力。
```
char　は文字型。
byte~ はデータ型。

charは0 ~ 65535まで数値を入れることができるが、charの意味する数値は文字を表している。
byte~ は数値を表している。

charの初期化の際に数値を代入することは良いが、
byte等のデータ型に数値を一度代入した後にcharに代入すると、同じ数値でもそれぞれ意味が異なるため、明示的なキャストが必ず必要になる。

## 接頭辞と接尾辞
**■接頭辞の種類**
| 進数 | 接頭辞 |
|:-----------|------------|
| ２進数     | 0b|
| ８進数     |0  |
| 10進数    |なし|
| 16進数    |0x |  

.........................................................................................................................................
**■接尾辞の種類**
| 進数 | 接頭辞 |
|:-----------|------------|
|double|「D」 もしくは　「d」|
|long  |「L」　もしくは　「l」|
|float |「F」　もしくは　「f」　|

**※他のプリミティブ型に対応する接尾辞はない。**

## 整数リテラルのルール
①アンダースコア「_」を利用することができる。
②リテラルの先頭と最後には記述できない。
③記号の前後には記述できない。
```java
int a = 100_000_000;   // ①問題なし。

int b = _100_000_000;  // ②コンパイルエラー

int c = 100_000_000_;  // ②コンパイルエラー 

int d = 0b_00111;      // ③コンパイルエラー

int e = 0x_00111;      // ③コンパイルエラー

float f = 1._0;        // ③コンパイルエラー

float f2 = 1.0_f;      // ③コンパイルエラー 
```

## 識別子のルール
①予約語での宣言はできない。
```java
int int = 10;
```
②使える記号はアンダースコア「_」、通貨記号のみ
```java
int _a = 20;

int $a = 30;

int _ = 40; // コンパイルエラー。
```
③数字から始めることはできない。（2文字目以降であれば可能）
```java
int 01 = 20;  // コンパイルエラー。

int $1 = 20;  // OK

int _0 = 20;  // OK
```
## varのルール
### ①varは右辺の代入演算子から型を推論する。

```java
public class Main {
  public static void main(String[] args){
    var i = 10;

    var m = new Main();  // OK

    var array = new int[]{1,2,3}; // OK
    var array2 = {1,2,3}          // new演算子での生成でないと推論が出来ずコンパイルエラー

     var value = sample();        // メソッドの戻り値から推論も可能。

     var value2 = () -> {};       // ラムダ式では型推論は使えないのでコンパイルエラー
                                  // ラムダ式の引数には使えるので注意！

     var list = new ArrayList<String>();  // OK （varはArrayList<String>型になる）
     var list = new ArrayList<>();        // OK （ジェネリクス内なしはObject型になる）
  } 

  public static String sample(){
    return "java";
  }
}
```

### <font color="red">②ローカル変数でしか利用できない。</font>

```java
public class Main {

  private var value;   // フィールド宣言では使えないのでコンパイルエラー

  public static void main(String[] args){
     var i = 10;
  } 

  public static void sample(var value){  // 引数宣言では使えないのでコンパイルエラー
    System.out.println("hello");
  }
}
```
### ③複合宣言もできない
```java
public class Main {
  public static void main(String[] args){
     var i = 10, i2 = 20;  // コンパイルエラー
  } 
}
```
## Stringクラス
### Stringオブジェクトの生成方法
**①""（ダブルクォーテーション）を使った文字列リテラルで生成**
**②newを使ってインスタンス化で生成**
**③StringクラスのvalueOfメソッドを使用する。**

```java
public class Main {
  public static void main(String[] args){
     
   String str = "Java";                  // ①

   String str2 = new String("Java");     // ②

   String str = String.valueOf("Java");  // ③
  } 
}


```
## Stringクラスのメソッド
**■charAtメソッド**
文字列の中から、引数で指定したindex番号の文字を戻す
```java
public class Main {
	public static void main(String[] args) {
	    
	   String str = "Java";
	   
	   System.out.println(str.charAt(2)); // vが出力
       System.out.println(str.charAt(4)); // index番号より多い数値を指定すると実行時エラー
	   
	   
	}
}
```
**■indexOfメソッド**
文字列の中から、引数で指定した文字のindex番号を返す。
指定した引数の文字が文字列にない場合、-1を返す。
```java
public class Main {
	public static void main(String[] args) {
	    
	   String str = "Java";
	   
	   System.out.println(str.indexOf("J"));  // 0 が出力。
	   System.out.println(str.indexOf("S"));  // -1 が出力。
	   
	}
}
```
**■substringメソッド**
文字列の中から、引数で指定した数値内の文字を抽出して返す。
```java
public class Main {
	public static void main(String[] args) {
	    
	   String str = "Java";
	   
	   System.out.println(str.substring(1,3));  // av が出力。
       System.out.println(str.substring(3,5));  //  実行時エラー。StringIndexOutOfBoundsException
	   
	}
}
```
substringメソッドの仕組み
```
   | J | a | v | a |
   0   1   2   3   4
　　　　　　　　　　　　　　↑　　　　　　　　　　　　　　↑

１ - ３　の間なので av
```
**■replaceメソッド・replaceAllメソッド**
文字列内の文字を、引数で指定した文字に置き換えるためのメソッド。
replaceメソッドは、char型の引数を２つ受け取る方と、
replaceメソッドは、charSequence型の引数を２つ受け取る方の２通りがある。
char型とcharsequence型を一つずつ受け取るものはないので、コンパイルエラーとなる。
```java
public class Main {
	public static void main(String[] args) {
	    
	   String str = "Java";
	   
       System.out.println(str.replace('a','b'));   // Jbvb　が出力。
       System.out.println(str.replace("av", "b")); // Jba　が出力。
       System.out.println(str.replace("av", 'b')); // コンパイルエラー。
	   
	}
}
```
replaceAllメソッドもreplaceメソッドと同様に、文字列内の文字を引数で指定した文字に置き換える。
違いとしては、replaceAllは第一引数に正規表現を使用することができ、正規表現にマッチした全ての文字を全て指定の文字（文字列）に変換できる。
```java
public class Main {
 
	public static void main(String[] args) {
		String str = "Java, html, css, python";
		System.out.println(str.replaceAll("[a-z]", "Go"));

       // JGoGoGo, GoGoGoGo, GoGoGo, GoGoGoGoGoGo が出力される。
	}
 
}
```
**■startsWith・endsWithメソッド**
文字列が引数で指定した文字から始まるか（終わるか）どうかを判定し、真偽を返す。
```java
public class Main {
 
	public static void main(String[] args) {
		String str = "Java";
		
		System.out.println(str.startsWith("J"));  // true
		System.out.println(str.endsWith("a"));    // true

	}
}
```
**■concatメソッド**
文字列に文字を連結するメソッド。
```java
public class Main {
 
	public static void main(String[] args) {
		String str = "Java";
		
		str = str.concat("Go");
        System.out.println(str);  // JavaGoが出力。

	}
}
```
---
### <font color="red">Stringクラスの罠</font>
---
#### <font color="red">①Stringクラスは不変のオブジェクトである。</font>
Stringクラスで生成した文字列は不変なオブジェクトになる。
なので、Stringで文字列を変更を加えた時は、
**<font color="red">新しい文字列インスタンスを都度生成している。</font>**
```java
public class Main {
 
	public static void main(String[] args) {
		String str = "Java";
		
		str += "Go";  // この時strの文字列にGoを追加しているのではなく、
                      // JavaGoという新しい文字列インスタンスを生成し、strに代入している。

	}
}
```
その他のStringメソッドも同様。
Stringメソッドで既存の文字列に変更を加えるメソッドは、都度文字列インスタンスを新たに生成している。
この時、**生成した文字列は変数に代入しないと、利用することはできない。**
```java
public class Main {
 
	public static void main(String[] args) {
		String str = "Java";
		
        str.concat("Go");
        str.replace('a','b'));
        str.substring(1,3);

        System.out.println(str); // Javaが出力。

	}
}
```
.................................................................................................................................................
## StringBuilderクラス
Stringクラスと同様に文字列を扱うクラス。
違いとしては、StringBuilderクラスは生成時に内部にバッファーを持った文字列を扱うことができる。
StringBuilderクラスは生成時、<font color="red">16文字分</font>の余分なバッファーを持って文字列を扱おうとする。
しかし、StringBuilderクラス生成時にコンストラクタで文字を指定して生成した場合、
<font color="red">16文字分 ＋ コンストラクタ内の文字列の長さ</font>分のバッファーを持って生成される。
```java
public class Main {
 
	public static void main(String[] args) {
		StringBuilder sb = new StringBuilder();
		StringBuilder sb2 = new StringBuilder("Java");

		System.out.println(sb.capacity());   // 16
		System.out.println(sb2.capacity());  // 20

	}
}
```



## StringBuilderクラスのメソッド
**■appendメソッド**
StringBuilder用の文字を連結するメソッド。
```java
public class Main {
	public static void main(String[] args) {
	    
		StringBuilder sb = new StringBuilder("Java");

		sb.append("GO");
		System.out.println(sb); // JavaGoが出力。
	   
	}
}
```
---
### <font color="red">StringBuilderクラスのポイント</font>
---
#### <font color="red">StringBuilderクラスは可変オブジェクトである。</font>
StringBuilderはStringクラスと違い可変長なので、代入せずとも文字列の変更ができる。
```java
public class Main {
	public static void main(String[] args) {
	    
	    String str = "GET";
		StringBuilder sb2 = new StringBuilder("Java");
		
		str.concat("POST");
		sb2.append("GO");

		System.out.println(str);   // GETが出力
		System.out.println(sb2);   // JavaGoが出力
	   
	}
}
```
.................................................................................................................................................

# 配列と操作

## 配列の宣言方法

### パターン①
大括弧とnew演算子を利用した宣言
```java
int[] array = new int[3]; 

int[][] array = new int[2][2];
```
#### ポイント

```java
// ①大カッコの中は整数しか記入できない。
int[] array = new int[2.3];  // コンパイルエラー

// ②配列の中で変数や計算ををすることができる。
int x = 3;
int y = 2;
int[] array = new int[x * y];

/*
 * ③多次元配列の場合、
 *  変数宣言時の大カッコの数と、代入する側の大カッコの数が違うと
 *  コンパイルエラーになる。
 */
int[][] array = new int[2];
int[] array = new int[2][3];

/*
 * ④多次元配列の場合、
 *  一次元配列目を空で宣言すると、二次元以降の宣言はできず、
 *  コンパイルエラーになる。
 */
int[][] array = new int[][2];

/*
 * ⑤new演算子の場合、
 *  変数宣言時と同時に宣言しなくても良い。
 */
int[] array;
array = new int[3];

```

### パターン②
{}を使用して初期化宣言
```java
int[] array = {1,2,3};
int[][] array = { {1,2},{3,4} };
```

#### ポイント
```java
/*
 * ①new演算子　＋ 大カッコと一緒に宣言ができる。
 *  一緒に宣言する場合、大カッコの中には整数値を入力してはいけない。
 *  整数値を入力するとコンパイルエラーになる。
 */
int[] array = new int[]{1,2}; //OK

int[] array = new int[2]{1,2}; //コンパイルエラー

/*
 * ②多次元配列の場合、
 *  変数宣言時の大カッコの数と、代入する側の{}の数が違うと
 *  コンパイルエラーになる。
 */
int[][] array = { {1,2},{3,4} }; //OK
int[] array = { {1,2},{3,4} };   //コンパイルエラー

/*
 * ③初期化子の場合、
 *  変数宣言時と同時に宣言しなくてはならない。
 *  
 *  分けて宣言したい場合、new演算子と大カッコも合わせて記述する。
 */
int[] array;
array = {1,2,3,4}; //コンパイルエラー

int[] array;
array = new int[]{1,2,3,4}; //OK

```
## 配列変数と配列要素

### 配列変数の出力
配列変数を直接出力すると、ハッシュコードが出力される。

```java
public class Main {
	public static void main(String[] args) {
	    
	    int[] array = new int[2];
		System.out.println(array);  //[I@722c41f4 が出力
	}
}
```

### 配列の要素のデフォルト値
配列の要素はデフォルト値で、以下のように用意されている。
| 型 | デフォルト型 |
|:-----------|------------:|
| 変数型      | 0           |
| 浮動小数点数型| 0.0        |
| 真偽型      | false       |
| 文字型      | ¥u0000      |   
| オブジェクト型 | null        |

要素に値を明示的に代入しない限りは、上記の値がセットされる。
```java
public class Main {
	public static void main(String[] args) {
	    
	    int[] array = new int[2];
		System.out.println(array[0]);  //0 が出力
	}
}
```
# 演算子と判定構文
## ==演算子とequalsメソッドによる比較の違い
#### <font color="red">概要</font>
Javaに２つの値を比較する方法が２種類ある。
**① ＝＝演算子による比較。**
**② equalsメソッドを使用した比較。**

＝＝演算子はデータ型の比較で使用することが基本であり、
equalsメソッドは参照型の比較で使用することが基本。

### ==演算子の場合
データ型の場合　→　値を比較し同値性を判断する。
参照型の場合　→　　参照先のアドレスを比較し、同値性を判断する。
```java
public class Main {
	public static void main(String[] args) {
	
	
	int a = 10;
	int b = 10;
	
 	Sample s1 = new Sample();
 	Sample s2 = new Sample();
	
 	Integer i1 = new Integer("1");
 	Integer i2 = new Integer("1");
	
	System.out.println(a == b);   // true
	System.out.println(s1 == s2); // false
	System.out.println(i1 == i2); // false
	
	}
}
```
### equalsメソッドの場合
**<font color="red">オーバーライドをせずに使用した場合</font>**
==演算子と同様の判断をする。


※例外あり。（詳細は後述）
※データ型ではequalsメソッドは使用できない。
```java
public class Main {
	public static void main(String[] args) {
	
	
	int a = 10;
	int b = 10;
	
 	Sample s1 = new Sample();
 	Sample s2 = new Sample();
	
 	Integer i1 = new Integer("1");
 	Integer i2 = new Integer("1");
	
	System.out.println(a.equals(b));   // コンパイルエラー
	System.out.println(s1.equals(s2)); // false
	System.out.println(i1.equals(i2)); // true
	
	}
}
```

**<font color="red">オーバーライドした使用した場合</font>**
オーバーライドした内容に沿って、判断する。

```java
public class Sample {
    public int num;
    
    public Sample(int num){
        this.num = num;
    }
    
    public boolean equals(Object obj){
        
        if(obj == null){
            return false;
        }
        
        if(obj instanseof Sample){
            Sample s = (Sample)obj;
            
            return s.num == this.num;
        }
        return false;
    }
}

public class Main {
	public static void main(String[] args) {
	
 	Sample s1 = new Sample("100");
 	Sample s2 = new Sample("100");
 	Sample s3 = new Sample("200");
	
 	Integer i1 = new Integer("1");
 	Integer i2 = new Integer("2");
	
	System.out.println(s1.equals(s2)); // true
    System.out.println(s1 == s2);      // false
    System.out.println(s1.equals(s3)); // false
	System.out.println(i1.equals(i2)); // false
	
	}
}
```

## String型の比較の注意点
### ==演算子の場合
```java
public class Main {
	public static void main(String[] args) {
	
 	String s1 = "Java";
 	String s2 = "Java";
 	String s3 = new String("Java");
	
    System.out.println(s1 == s2);      // ①true

    System.out.println(s1 == s3);      // ②false
	System.out.println(s2 == s3);      // ②false

	System.out.println(s1.equals(s2)); // ③true
	System.out.println(s1.equals(s3)); // ③true
	System.out.println(s2.equals(s3)); // ③true
	
	}
}
```
**①解説**
String型はオブジェクト型だが、＝＝演算子の比較でもtrueが返される。
これは文字列を生成する際、以下のような処理を行なっているからである。

■一度生成された文字列は<font color="red">コンスタントプール</font>と呼ばれる別領域に定数として一度保存される。

■そして、もし同じ文字列が再度生成された場合は、そのコンスタントプールから同じ文字列のものを使い回す。

⇨ 結果としてs1とs2は同じ参照先が代入されており、trueとなる。

---

**②解説**
①の解説は、newを使用せず、””（ダブルクォーテーション）を使用して生成された場合に起きる処理となる。
newを使用して文字列を生成した場合は新たなインスタンスとして生成をする。

⇨ s1とs3は別々の参照先が代入されているので、falseとなる。

---

**③解説**
equalsメソッドは厳密にはオブジェクトの持つ<font color="red">**値**</font>を比較し、その値が同じかを判断する。
なので、Integerの持つ数値・Stringの持つ文字列を比較対象としている。

⇨ 結果、s1.s2.s3は全て同じ文字列を持つので、参照先が違っていてもtrueとなる。

## Stringのinternメソッドについて
Stringクラスのinternメソッドを使用すると、これまでの解説とは少し違った動きをする。
```java
public class Main {
	public static void main(String[] args) {
	
 	String s1 = "Java";
    String s2 = "Java";
 	String s3 = new String("Java");
    String s4 = new String("Java");
	
    System.out.println(s1.intern() == s2.intern());      // true

    System.out.println(s1.intern() == s3.intern());      // true
	
    System.out.println(s2.intern() == s3.intern());      // true	

    System.out.println(s3.intern() == s4.intern());      // true
	}
}
```
internメソッドを使用すると、newで生成したs3インスタンスを==演算子で比較してもtrueとなる。

これはinternメソッドが、<font color="red">**変数の持つ文字列をコンスタントプールを含むメモリの中から探し出し、再利用する**</font>という処理をするからである。
同じ文字列を持つインスタンスが複数あったとしても、internメソッドで返す参照先は常に同じで１つだけである。
よって、s1~s4には全て同じ参照先がreturnとして返されているため、全てtrueとなる。


## if文

■if文はカッコ{}を省略できるが、省略した場合if文の処理として見なされるのは条件式の直後の処理だけ
```java
public class Main {
	public static void main(String[] args) {
	
 	if(false)
      System.out.println("hello");
      System.out.println("See you");
  }  // See youだけが表示
}
```

## switch文

■switch文の条件式が戻せる型には制限があり、戻せるのは以下の型だけ

・int型以下のデータ型（int,short,byte,char）
・String型
・列挙型

■switch文のcase値として利用できるのは、
<font color="red">**・定数（finalで宣言された変数かリテラル）**</font>か<font color="red">**コンパイル時に値を決められるもの**</font>
<font color="red">**・条件式の戻す値と同じ型か互換性のある型**</font>
<font color="red">**・nullではない※**</font>
の３つの決まりがある。

<font color="red">※条件式にnullを使用すると、NullpointerExceptionが返される。</font>

**悪い例（全てコンパイルエラー）**
```java
public class Main {
	public static void main(String[] args) {

		double d = 3.14;

		switch(d){
		    
		    case "100.0": System.out.println("OK");  // 互換性がないので×
		    break;
		    
		    case 3.14 : System.out.println("OK");    // double型は返せないので×
		    break;
		    
		    case null : System.out.println("OK");   // nullは使用できない
		    break;
		    
		    case d : System.out.println("OK");     // 定数じゃないので×
		    break;
		}
	}
}
```
**良い例**
```java
public class Main {
	public static void main(String[] args) {

		final int NUM = 100;

		switch(NUM){
		    
		    case NUM: System.out.println("OK");   // 定数
		    break;
		    
		    case 1000 : System.out.println("OK"); // リテラル
		    break;
		    
		    case 2*20 : System.out.println("OK"); // コンパイル時に確定する数値
		    break;
		    
		    case '9' : System.out.println("OK");  // 互換性
		    break;
		    
		    case 'a' : System.out.println("OK");  // 互換性
		    break;
		}
	}
}
```
---

# インスタンスとメソッド
## staticについて
staticがついたフィールドを、`クラス変数`という。
クラス変数はクラス毎に作られる変数。

クラス単位の変数なので、インスタンスを作成してもクラス変数は全てのインスタンス間で共有される。

```java
// Aクラス
public class A {
    
    public static int num = 10;
}

// Mainクラス
public class Main {
	public static void main(String[] args) {
	    
	    A a = new A();
	    
	    A a2 = new A();
	    
	    a.num = 10;
	    
	    a2.num = 50;
	    
	    System.out.println(a.num);  // 50
	    System.out.println(a2.num); // 50
	    System.out.println(A.num);  // 50
	}
}
```

### ポイント
**①staticで修飾されたフィールドやメソッドは、static領域という領域に配置される。**

**②staticなフィールドはインスタンスを作らなくても使用できる。**

**③staticなフィールドにアクセスするには方法は２つ。**
`①クラス名.フィールド名`
`②インスタンス名.フィールド名`

**④staticで修飾されたフィールドやメソッド　<font color=red>が</font>　アクセスできるのは、
staticで修飾されたフィールドやメソッド　<font color=red>だけ</font>　である。**
```java
public class Main {
    
    static int a = 10;
    
     public static void main(String[] args){
        
        // static　から　static
	    System.out.println(Main.a);
	    
    }
}
```

**⑤staticで修飾されたフィールドやメソッド　<font color=red>には</font>　、
staticで修飾されていないフィールドやメソッドもアクセスできる。**
```java
public class Main {
    
    static int a = 10;
    
    public int b = 20;
    
     public static void main(String[] args){
        
        // static　から　static
	    System.out.println(Main.a); // 10
	    
	    /*
         * コンパイルエラー。
         * 変数bはインスタンス変数なので、インスタンス化しないとそもそも呼び出せない。
         */
	    System.out.println(Main.b); 
    }
}
```
---

## オーバーロード
### オーバーロードとは
メソッドの多重定義。同名のメソッドを複数宣言すること。
オーバーロードの条件は、`メソッドの引数が異なること`であり、

①引数の<font color="red">型</font>
②引数の<font color="red">数</font>
③引数の<font color="red">順番</font>

が異なればオーバーロードである。

##### 注意
<font color="red">オーバーロードにおいて、戻り値が同じか同じではないかは条件には入らない。
戻り値が違っていても、引数が同じならオーバーロードにはならない。
戻り値が同じでも、引数が違うならオーバーロードになる。</font>

◆引数の変数名だけが違う
◆戻り値だけが違う

はコンパイルエラーになる。
```java
public class Main {
    
     public static void main(String[] args){
        
    }
    
    // オーバーロード
    public static void main(int[] args){
        
    }
    
    // オーバーロード
    public static void main(String[] args,int num){
        
    }
    
    // 戻り値だけ違う。　コンパイルエラー
    public static String main(String[] args){
        
        return "hello";
    }
    
    // 引数名だけが違う。　コンパイルエラー
    public static void main(String[] arg){
        
    }
    
}
```

### オーバーロードの優先順位について
オーバーロードの際<font color="red">引数は異なるが引数に互換性にがある場合、</font>一番近いもの（
厳密な方）が優先されて呼び出される。
```java
import java.util.List;
import java.util.Collection;
import java.util.ArrayList;

public class Sample {
    
    public void message(Collection collection) {
        
        System.out.println("A");
    }
    
    public void message(List list) {
        
        System.out.println("B");
    }
}

public class Main {
    
     public static void main(String[] args){
         
         List<String> list = new ArrayList<>();
         
         Sample s = new Sample();
         
         s.message(list);  // Bが出力
         
         
    }
}
```


---

## コンストラクタ
インスタンスが利用される前に前処理を行うメソッドのこと。

### ポイント
#### コンストラクタの３つのルール

`①メソッド名はクラス名と同じにすること`
`②戻り値は記述できない`
`③newと一緒にしか使えない（インスタンス生成時以外は呼び出せない）`

#### 注意
コンストラクタにアクセス修飾子の制限は特にないので、基本的にどのアクセス修飾子も付与できる。

### コンストラクタの初期化
#### 初期化子
初期化子を使うことで、コンストラクタが<font color="red">実行される前に</font>実行される処理を記述することができる。
初期化子を記述すると、オーバーロードしたコンストラクタ全てで初期化子の処理が一度実行される。

<font color="red">※初期化子はインスタンスが呼び出された時にしか利用されない。</font>
```java
public class Sample {

   // 初期化子
   {
       System.out.println("B");
   }
   
   public Sample(){
       System.out.println("A");
   }

   public Sample(String str){
       System.out.println("A");
   }
}
```

#### static初期化子
インスタンス生成時ではなく、クラスがロードされた段階で何らかの処理を実装してほしいときは、`static初期化子`を利用する。
```java
   // 初期化子
   static {
       System.out.println("B");
   }
   
   public Sample(){
       System.out.println("A");
   }

   public Sample(String str){
       System.out.println("A");
   }
}
```

#### デフォルトコンストラクタ
コンストラクタを明示的に定義しなかった場合、コンパイラが引数なしのコンストラクタをコンパイル時に追加する。
このコンストラクタをデフォルトコンストラクタという。

##### 注意
①引数なしのコンストラクタをデフォルトコンストラクタというわけではない。
②デフォルトコンストラクタは、明示的にコンストラクタを定義した場合は追加されない。
<font color="red">※引数ありのコンストラクタを定義してしまうと、それもデフォルトコンストラクタが追加されない条件に当てはまってしまうので、引数有りのコンストラクタ以外を呼び出せなくなってしまう。
解決するには、引数なしのコンストラクタを明示的に定義しなければいけない。
</font>
```java
public class Sample {
    
   private String name;
   
   // public Sample(){
   // }
   
   public Sample(String name){
      this.name = name;
   }
}

public class Main {
     public static void main(String[] args){
        
     Sample s = new Sample();  // コンパイルエラー
    }
}
```

### コンストラクタとthis
<font color="red">コンストラクタ内でオーバーライドした別のコンストラクタを呼び出す</font>には、コンストラクタ内で`this`を記述する。
```java
public class Sample {
    
   private String name;
   
    public Sample(){
      // 下のコンストラクタを読んでいる。
      this("AAA");
      System.out.println("A");
    }
   
   public Sample(String name){
      this.name = name;
   }
}
```

##### 注意
コンストラクタ自体の記述の順番は関係ないが、thisは一番最初に記述しなければならない。
<font color="red">thisを使って別のコンストラクタを呼び出す際は、呼び出す前に何らかの処理を記述してはいけない。</font>
```java
public class Sample {
    
   private String name;
   
   // コンパイルエラー
    public Sample(){
      System.out.println("A");
      this("AAA");
    }
   
   public Sample(String name){
      this.name = name;
   }
}
```
---
### <font color="red">thisの使い方の注意点</font>
---
thisは別のコンストラクタを呼び出す以外にも、インスタンス内に定義されたフィールドやメソッドを呼び出す際にも使用する。
```java
public class A {
 String name;
  public void methodA(String name){
      this.name = name;
      this.callName();
  }
  
  public void callName(){
      System.out.println(this.name);
  }
}

public class Main {
	public static void main(String[] args) {

     A a = new A();
     a.methodA("sample"); // sampleと出力。
	}
}
```
このthisを仮にローカル内でつけなかった場合、フィールドと引数（ローカル変数）の２箇所あることになるが、この場合、ローカル変数側の利用を優先される。
```java
public class A {
 String name;
  public void methodA(String name){
      name = name;   // thisを削除したので、代入式の左辺は引数（ローカル変数）のnameということになる。
                     // つまりこの式は、引数nameに引数nameを代入するという式になる。
      this.callName();
  }
  
  public void callName(){
      System.out.println(this.name);
  }
}

public class Main {
	public static void main(String[] args) {

     A a = new A();
     a.methodA("sample"); // nullと出力。（Aクラスのフィールドnameには何も代入されていないから。）
	}
}
```
しかし、ローカル変数内にフィールド名と同じ変数がなければ、thisを使わなくてもフィールドにアクセスすることはできる。
```java
public class A {
 String name;
  public void methodA(String str){
      name = str;
      this.callName();
  }
  
  public void callName(){
      System.out.println(this.name);
  }
}

public class Main {
	public static void main(String[] args) {

     A a = new A();
     a.methodA("sample");  // sampleと出力。
	}
}
```
特にインスタンス内のフィールドにアクセスする問題の場合、

**①ローカル変数（引数の宣言）が、フィールド名と同じになっているかどうか**
**②同じの場合、代入式の左辺にthisが付いているかどうか**

を意識するとよい。

---

## アクセス修飾子

| 修飾子 | 説明 |
|:-----------|------------|
| public     | 全てのクラスでアクセス可能。            |
| protected  | 同じパッケージもしくは継承しているサブクラスからのみアクセス可能。        |
| なし        | 同じパッケージのみアクセス可能。       |
| private    | クラス内からのみアクセス可能。      |   

```java
package ex1;
public class Sample {
    
   private String str = "str";
   private String str2 = "str2";
   private String str3 = "str3";
   private String str4 = "str4";
   
   public String getStr(){
       return str;
   }
   
   protected String getStr2(){
       return str2;
   }
   
   String getStr3(){
       return str3;
   }
   
   private String getStr4(){
       return str4;
   }
}

package ex2;
import ex1.Sample;
public class Sample2 extends Sample {

}

package ex2;

public class Main {
    
     public static void main(String[] args){
         
         Sample2 s = new Sample2();
         
         System.out.println(s.getStr());

        // コンパイルエラー。（継承関係なしのMainクラス　＋　違うパッケージからのアクセス）
        System.out.println(s.getStr2()); 

        // コンパイルエラー。（違うパッケージからのアクセス）
        System.out.println(s.getStr3());
        
        // コンパイルエラー。（違うクラスからのアクセス）
        System.out.println(s.getStr4());
    }
}
```

クラス宣言でつけられるアクセス修飾子は、
`public`　か　`デフォルト`　の２つだけ。

---

## 変数の初期化について
変数には初期化をしなくても良いケースと、初期化をしなければいけないケースがある。

### <font color="red">しなくてはいけないケース</font>
**①ローカル変数**
**②finalで修飾されたインスタンス変数・クラス変数。**

これら二つは必ず初期化を行わなければならず、行わなかった場合コンパイルエラーとなる。
インスタンス変数・クラス変数の場合、初期化を行う方法は２つ。
```java

public class Sample {
    
    // 方法①
   private final String STR = "str";
   
   
   // 方法②
   private final String STR2;
   
   public Sample(String str2) {
       this.STR2 = str2;
   }
}
```

### <font color="blue">しなくても良いケース</font>
その他インスタンス変数・クラス変数など

こちらの場合は、以下のような初期値がデフォルトで設定される。
| 型 | デフォルト値 |
|:-----------|:------------|
| int        | 0          |
| double     | 0.0        |
| boolean    |false       |
| String等参照型| null     |  

---

# クラスの継承・インターフェース・抽象クラス
## クラスの継承
継承のイメージは以下の通り。
継承されたクラス（スーパークラス）と、継承したクラス（サブクラス）があり、
サブクラスは、スーパークラスのインスタンスと、　**差分**　のインスタンスを両方合わせて作られている。
![スクリーンショット 2022-07-04 23.55.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/754263/edccbe81-af9e-8bae-b1ea-1caf950bf21f.png)

※このイメージがないと、ポリモーフィズムの問題で躓くので注意。

---

### <font color="red">継承を行う上での罠</font>
---

#### <font color="red">①継承で引き継げないものがある。</font>

**◆private で修飾されたフィールド・メソッド**
**◆コンストラクタ**

...........................................................................................................................................

#### <font color="red">②クラスの多重継承は禁止されている。</font>
複数のスーパークラスから継承をすることはできない。（extends 〜　は１つだけ）

...........................................................................................................................................

#### <font color="red">③コンストラクタの呼び出し（super）</font>
サブクラスのコンストラクタを処理する際、まずスーパークラスのコンストラクタから処理される。
```java
public class A {
 public A () {
  System.out.println("A");
 }
}

public class B {
 public B () {
  System.out.println("B");
 }
}

public class Main {
 public static void main (String[] args) {
  B b = new B();  // A・Bの順番で出力される。
 }
}
```
この時、サブクラスでスーパークラスのコンストラクタを明示的に呼ぶには、以下のように記述する。
```java
public class A {
 public A () {
  System.out.println("A");

 public A (String a) {
  System.out.println("AA");
  }
 }
}

public class B {
 public B () {

  super();         // Aクラスのコンストラクタを呼び出す。
  super("引数あり"); // 引数ありのスーパークラスのコンストラクタの呼び出し

  System.out.println("B");
 }
}
```
---
### <font color="red">superの注意点</font>
---
・super()で呼び出せるのは直前に継承したスーパークラス（１つ上の）のコンストラクタのみ。
・super()は２つ書けない。
```java
public class A {
 public A(String str, int num){
     System.out.println(str + num);
 }
}

public class B extends A {
    public B(String str, int num, int num2){
     System.out.println(Str + num + num2);
 }
}

public class C extends B {
  public C(){
     super("A",10);        // Aクラスのコンストラクタを呼び出そうとしてコンパイルエラー。

     super.super("A",10);  // Aクラスのコンストラクタを呼び出そうとしてコンパイルエラー。

     System.out.println("C");
 }
}
```
・super()は一番上に記入しなければいけない。※super()の上にコードは書けない。
```java
public class A {
 public A(){
     System.out.println("A");
 }
}

public class B extends A {
    public B(){
     System.out.println("B");
     super();   // コンパイルエラー。
 }
}

public class Main {
	public static void main(String[] args) {

     B b = new B();
	}
}
```
・<font color="blue">引数なしのsuper()は、明示的に記入しなければ自動で生成される。</font>
```java
public class A {
 public A(){
     System.out.println("A");
 }
}

public class B extends A {
    public B(){
　　　　　　　　　// super(); が自動で生成され、Aのコンストラクタを呼び出す。
     System.out.println("B");
 }
}

public class C extends B {
  public C(){
　　　　　　　　　　// super(); が自動で生成され、Bのコンストラクタを呼び出す。
     System.out.println("C");
 }
}


public class Main {
	public static void main(String[] args) {

     C c = new C();  // A,B,Cの順で出力される。
	}
}
```

ここでの問題は、３個目の注意点。
スーパークラスで　**引数有りのコンストラクタだけ**　を明示的に記入し、super()を自動生成に任せた場合、以下の処理はコンパイルエラーになる。
```java
public class A {

public A (String a) {
    System.out.println("AA");
 }
}

public class B extends A {
public B () {
    System.out.println("B");
 }
}

public class Main {
	public static void main(String[] args) {
		
		B b = new B();
	}
}
```
自動生成で追加されるのは　**引数なしのsuper()**　であり、スーパークラスのAクラスには引数なしのコンストラクタはない。
また、Aクラスでは引数有りのコンストラクタを明示的に定義したので、　**デフォルトコンストラクタ**　も自動生成されない。
コンパイルエラーを解決するには、Aクラスに　**引数なしのコンストラクタ**　を明示的に定義する必要がある。
...........................................................................................................................................

---

### <font color="red">ポリモーフィズム</font>
---
インスタンス宣言時、型宣言を`スーパークラス`でインスタンスを`サブクラス`で宣言するやり方を**ポリモーフィズム**という。
```java
public class A {}

public class B extends A {}

public class Main {
	public static void main(String[] args) {
		
		A a = new B();
	}
}
```
### <font color="red">ポリモーフィズムの注意点</font>
----
#### <font color="red">フィールドはスーパークラスを参照する。</font>
```java
public class A { public String name = "A"; }

public class B extends A { public String name = "B"; }

public class Main {
	public static void main(String[] args) {
		
		A a = new B();
        System.out.println(a.name);  // Aが出力。
	}
}
```
#### <font color="red">メソッドはオーバーライドされているかで決まる。</font>
◆オーバーライドされているパターン
```java
public class A {
 private String name = "A"; 
 
 public String getName(){
    System.out.println("A");
    return this.name;
  }
}

public class B extends A {
    
  private String name = "B"; 

  public String getName(){
    System.out.println("B");
    return this.name;
  }
}

public class Main {
	public static void main(String[] args) {
		
		A a = new B();
		
		System.out.println(a.getName());  // B B　と出力。
	}
}
```
◆オーバーライドされていないパターン
```java
public class A {
 private String name = "A"; 
 
 public String getName(){
    System.out.println("A");
    return this.name;
  }
}

public class B extends A {
    
  private String name = "B"; 

}

public class Main {
	public static void main(String[] args) {
		
		A a = new B();
		
		System.out.println(a.getName());  // A A　と出力。
	}
}
```
..........................................................................................................................................

## インターフェース
### インターフェースとは
クラスから型だけを取り出したもの。

---
### <font color="red">インターフェースの暗黙的ルールと注意点</font>
---
#### <font color="red">①アクセス修飾子はpublicのみ</font>

インターフェースは実装されることを前提とされるものなので、インターフェース自身の定義・メソッド・フィールドはすべて<font color="red">public</font>のみ修飾が可能。


また、<font color="red">アクセス修飾子の記述を省略した場合、自動的にpublic</font>として見なされる。

⇨<font color="red">**interfaceのメソッドを実装（オーバーライド）するには、必ずアクセス修飾子はpublicである必要がある。**</font>

...........................................................................................................................................
#### <font color="red">②メソッドは実装を記述できない。</font>

インターフェースで定義できるメソッドは、基本的に実装を記述できない。また、
インターフェースで定義する<font color="red">実装なしのメソッドは、public＋abstract</font>と見なされる。
```java
interface A {  // アクセス修飾子が省略されているが、publicである。

  void methodA();  // アクセス修飾子が省略されているが、public＋abstractである。
                   // また、{} を用いた実装は記述できない。

}
```

しかし実装に関しては例外があり、<font color="red">default修飾子で定義するデフォルトメソッド、</font>もしくは、
<font color="red">static修飾子で定義するstaticメソッド</font>であれば、実装メソッドを定義できる。
```java
interface A {  

  void methodA();

  default void methodB(){};  // defaultメソッドもpublicである。
  static void methodC(){};　　  // staticはインスタンス化せずに利用できるからOK。

}
```
...........................................................................................................................................
#### <font color="red">③defaultメソッドで、継承したメソッドを実装することができる。</font>
defaultメソッドで継承・実装したメソッドを実装することはできる。
```java
interface A {  

  void methodA();

}

interface B implements A {

  default void methodA () {};

  void methodB();
}
```
またdefaultメソッドを継承したメソッドから、元のデフォルトメソッドを呼び出すには、以下のように記述する。

**インターフェース名.super.メソッド名();**

```java
interface A {  
  default void methodA(){};
}

class B extends A {
  
  @Override 
  public void methodA () {

   A.super.methodA();  // ←

  };

  void methodB();
}
```
...........................................................................................................................................
#### <font color="red">④フィールドはpublic ＋ static ＋ finalになる。</font>
インターフェースでフィールドを定義すると、自動的に public ＋ static ＋ finalになる。
```java
interface A {  

  int NUMBER = 100;  // publicであり、static（インスタンス化不要）な定数（final）である。

}
```
...........................................................................................................................................
#### <font color="red">⑤インターフェースは多重継承可能。</font>
インターフェースはクラスと違い、多重継承が可能である。
```java
public class C extends A, B {};
```
また、実装も複数行うことが可能。
```java
public class C implements A, B {};
```
...........................................................................................................................................
#### <font color="red">⑥菱形継承問題</font>
継承・実装どちらも複数対応ができるIFが故に起こる問題。
◆パターン１
```java
interface A {
  public void A();
}

interface B extends A {
  @overide 
   default public void A(){
    System.out.println("B");
 }
}

interface C extends A {
  @overide 
   default public void A(){
    System.out.println("C");
 }
}

public class D implements B, C {
  @overide 
   public void A(){
    super.sample();    // コンパイルエラー。
    B.super.sample();  // B　と出力。
 }
}
```
この場合、継承している２つのインターフェースどちらも同じメソッドを実装しているため、どちらのメソッドを呼び出せば良いのか判断できずコンパイルエラーとなる。

上記の場合、解決する方法は、superの前にインターフェース名をつけ、どちらのスーパークラス（インターフェース）を呼び出すのか明示的に記述する必要がある。

◆パターン２
```java
public interface A{
  public Iterable A();
}

public interface B extends A{
  public Collection B();
}

public interface C extends A{
  public Path C();
}

public class D extends B, C{
 
}
```
上記の場合は、共変戻り値を利用した菱形継承問題。
上記の場合問題なのは、BインターフェースとCインターフェースとで、オーバーライドした際に戻り値が異なっていること。
この場合Dクラスでは、<font color="red">戻り値の都合により、どちらの戻り値を戻すメソッドを引き継げば良いのかがわからず、コンパイルエラーになる。</font>
...........................................................................................................................................
#### <font color="red">⑦型は使えるがインスタンス化はできない</font>
インターフェースを継承した場合、スーパークラスとして型の利用をすることはできるが、インターフェース自身をインスタンス化することはできない。
```java
public interface A{
  public void A();
}

```
## 抽象クラスと具象クラス・抽象クラスの実装
### 抽象クラス
抽象メソッドと、具象メソッドを持つことができるクラスのこと。
抽象クラスの定義には、<font color="red">abstract</font>が必須。
```java
abstract class A {

  abstract public void methodA();
  
  public void methodB(){
      System.out.println("B");
  }
}
```

### 具象クラス
具象メソッドを持つクラスのこと。抽象メソッドは持てない。

---
### <font color="red">抽象クラスの罠</font>
---

#### <font color="red">①フィールドを定義できる。</font>
抽象クラスは同じように抽象メソッドを持つインターフェースと混同してしまうところがある。
抽象クラスではフィールドを定義することはできる。
インターフェースのように、public ＋　finalにもならない。
...........................................................................................................................................
#### <font color="red">②クラスのアクセス修飾子は暗黙的にpublic</font>
抽象クラスはアクセス修飾子を記載しないが、暗黙的にpublicになる。
```java
abstract class A { // 抽象クラスは暗黙的にpublic
}
```
...........................................................................................................................................
#### <font color="red">③抽象クラスの抽象メソッドは、明示的なabstractの記載が必須。</font>
インターフェースのように、暗黙的にabstractとpublicで認識されるわけではなく、明示的にabstractを記入する必要がある。
```java
abstract class A {

  public void methodA();  // abstractで宣言していないので、コンパイルエラーになる。
  
  public void methodB(){
      System.out.println("B");
  }
}

public class B extends A {
    @Override
    public void methodA(){
        System.out.println("A");
    }
}

public class Main {
	public static void main(String[] args) {
		
		B b = new B();
	}
}
```
...........................................................................................................................................
#### <font color="red">④抽象メソッドを持っていなくても抽象クラスを定義することができるが、抽象メソッドを持っているクラスは　強制的に　抽象クラスになる。</font>
抽象クラスは必ず抽象メソッドを持っていなければいけないわけではない。
具象メソッドだけを持っていても、abstractで宣言されていれば、それは抽象クラスとなる。
```java
public abstract class B {  // 具象メソッドしか持っていないが、抽象クラス

  public void methodA(){
      System.out.println("A");
  }
  
  public void methodB(){
      System.out.println("B");
  }
}

public class Main {
	public static void main(String[] args) {
		
		B b = new B(); // 具象メソッドしかないが抽象クラスなので、インスタンス化はできずコンパイルエラー
	}
}
```
しかし、abstract宣言していないクラスに抽象メソッドを持たせると、abstract宣言を追加し、抽象クラスとして宣言しなければコンパイルエラーになる。
```java
public class A {  // 

  abstract public void methodA();
  
  public void methodB(){
      System.out.println("B");
  }
}
```
...........................................................................................................................................
#### <font color="red">⑤抽象メソッドはprivate以外も修飾できる。</font>
インターフェースと違い、抽象クラス内で宣言した抽象メソッドは、private以外のアクセス修飾子は修飾することができる。
```java
public interface A {
 void methodA();  // アクセス修飾子なしは暗黙的にpublic。
                  // 他のアクセス修飾子をつけたらコンパイルエラー
}


abstract public class B {

  abstract protected void methodA(); // 抽象メソッドならアクセス修飾子は
                                     // public ~ protectedまでOK。
  
  public void methodB(){
      System.out.println("B");
  }
}


public class C extends B {
    @Override
    public void methodA(){
        System.out.println("A");
    }
}
```

⇨ 抽象メソッドも具象クラスで実装（オーバーライド）する必要があり、そのためにはアクセス修飾子を緩くしなければいけない。
...........................................................................................................................................
#### <font color="red">⑥抽象クラスで必ず継承して利用する。</font>
抽象クラスは基本的に継承して利用する。
抽象クラスは単体でインスタンス化することはできないので、具象クラスが継承して利用する。
また、抽象メソッドを定義した抽象クラスは、継承した具象クラスで必ずオーバーライドし、実装する必要がある。

```java
abstract class A {

  public void methodA();
  
  public void methodB(){
      System.out.println("B");
  }
}

abstract class B extends A {
  @Override 
  public void methodA(){};  // 継承した具象クラスで必ず実装する。
  
  public void methodB(){
      System.out.println("B");
  }
}
```

また、抽象メソッドを実装するのは最後に継承した具象クラスで良い。
```java
abstract class A {
 abstract protected void methodA();
}

abstract class B extends A {

  public void methodB(){
      System.out.println("B");
  }
}

public class C extends B {
    @Override
    public void methodA(){
        System.out.println("A");
    }
}

public class Main {
	public static void main(String[] args) {
		
		C c = new C();
		c.methodA();  // Aと出力。
	}
}
```
---
### <font color="red">オーバーライド</font>
---
#### オーバーライドとは
メソッドの継承のこと。
継承元に定義されているメソッドを、継承先のメソッドで再定義（上書き）することを指す。
...........................................................................................................................................
#### <font color="red">オーバーライドの条件</font>
・引数の型・順番・数がすべて同じであること。
```java
public class A {
  public String methodA(String a, int b){
    return a;
  };
}

public class B extends A {
  @Override 
  public String methodA(String a, int b){
    System.out.println(b);
    return a;
  };
}
```
・戻り値が同じか、サブクラス型であること。
```java
public class A {
  public Collection methodA(){};
}

public class B extends A {
  @Override 
  public Collection methodA(){};
}

public class C extends A {
  @Override 
  public List methodA(){};
}
```
・アクセス修飾子が同じか、より緩いものであること。
```java
public class A {
  void methodA(){ return ""; };
}

public class B extends A {
  @Override 
  public void methodA() {  // protectedでも可。
    System.out.println("B");
  };
}
```
・throwsで宣言する例外は、スローする例外と同じ型かサブクラス型であること。
```java
public class A {
 public void methodA()throws Exception{};
}

public class B extends A{
  @Override 
  public void methodA()throws ClassCastException{};
}
```
# 関数型インターフェース・ラムダ式
## java.util.functionパッケージに属する標準関数型インターフェース
### <font color="red">①Predicate\<T\></font>
何らかの処理の結果として、boolean型の値を返すための関数。
testメソッドを利用する。
```java
import java.util.function.Predicate

public class Sample {
    public static void main(String[] args){
      Predicate<String> p = str -> {
         return "".equals(str);
       };
       System.out.println(p.test(args[0]));
    }
}
```
### <font color="red">②Supplier\<T\></font>
何も受け取らず、結果だけを返す関数。
getメソッドを利用する。
```java
import java.util.function.Supplier

public class Sample {
    public static void main(String[] args){
      Supplier<String> func = () -> {
         return "Hello.";
       };
       System.out.println(p.get());
    }
}
```
### <font color="red">③Consumer\<T\></font>
引数を受け取り、処理は戻さない。
acceptメソッドを利用する。
```java
import java.util.function.Consumer

public class Sample {
    public static void main(String[] args){
      Consumer<String> func = str -> {
         System.out.println("Hello" + str);
       };
       System.out.println(func.accept("java"));
    }
}
```
### <font color="red">④Function\<T,R\></font>
引数を受け取り、指定された型（R）の結果を返す。
applyメソッドを利用する。
第一引数を受け取り、第二引数を返す。
```java
import java.util.function.Function

public class Sample {
    public static void main(String[] args){
      Function<String,Integer> func = (str) -> {
         return Integer.parseInt(str);
       };
       System.out.println(func.apply("100") * 2);
    }
}
```
## 関数型インターフェースとラムダ式
### 関数型インターフェース
定義されている抽象メソッドが<font color="red">1つだけある</font>インターフェース。
※複数存在するインターフェースをラムダ式で実装しようとすると、コンパイルエラーとなるので注意。

### ラムダ式
関数型インターフェイスを実装したクラスのインスタンスを、ごく短いコーディング量でとても簡単に作れてしまう文法のこと。
```java
interface Function {
  void test(String val);  // 抽象メソッド１つ
}

public class Main {
  public static void main(String[] args){
    
    Function func = (var) -> { System.out.println(val); };
    func.test("A");
  }
}
```
---
### <font color="red">関数型インターフェース・ラムダ式の罠</font>
---
### ①<font color="red">ラムダ式のスコープは、それを囲むブロックと同じスコープを持つ</font>
ラムダ式と、ラムダ式を囲むブロックは同じスコープになる。
＝ラムダ式で宣言する変数（ローカル変数）が、ラムダ式の前のブロックで既に宣言されていたら、コンパイルエラーになる。
```java
public class Main {
  public static void main(String[] args){
    
    String var = "Hello";
    
    Function func = (var) -> { System.out.println(val); }; // コンパイルエラー
  }
}

/**
 * 上記の式では、ラムダ式funcの前にmainメソッドブロックで既に変数varを宣言している。
 * 　funcの引数でvarを宣言しているが、同名のローカル変数は２つ宣言はできないので、コンパイルエラー。
 */
```
...........................................................................................................................................
### ②<font color="red">ラムダ式がアクセスする変数は実質的なfinal（定数）でなければならない。</font>
ラムダ式でアクセスできる変数は、実質的にfinal（変更できない・しない）な変数でなければならず、変更するとコンパイルエラーになる。
実質的というのは、finalで宣言されていなくても、変更されない・されていなければアクセスできる。
```java
interface Function {
  void test();
}

// 成功例
public class Sample {
  public static void main(String[] args){
    String str = "Hello";
    Function func = () -> { System.out.println(str); }; //アクセス可能。正常終了。
  }
    func.test();
}

// コンパイルエラー①
public class Sample {
  public static void main(String[] args){

    String str = "Hello";

    Function func = () -> { 
      str = "See you";
      System.out.println(str);  // ラムダ式内で変更されているのでコンパイルエラー。
    };
      func.test();
  }
}

// コンパイルエラー②
public class Sample {
  public static void main(String[] args){

    String str = "Hello";

    Function func = () -> { 
      System.out.println(str);  // ラムダ式の後の外で変更されていてもコンパイルエラー。
    };
    str = "See you";
    func.test();
  }
}
```
...........................................................................................................................................
## ラムダ式の省略
### ①()の省略
ラムダ式では引数が1つだけの場合、（）を省略できる。
```java
public class Main {
	public static void main(String[] args) {
	// 通常	
	Function f = (name) -> { return "hello" + name; };

   // 省略
   Function f = name -> {return "hello" + name; };
	
	System.out.println(f.test("Java"));
  }
  
  private static interface Function {
      String test(String name);
  }
}
```
### ②{}の省略
実行したい処理が一つだけの場合、{}が省略できる。
また、この時{}を省略したら、<font color="red">必然的にreturnも省略しなければいけない。</font>
```java
public class Main {
	public static void main(String[] args) {

   // コンパイルエラー
   Function f = name -> return "hello" + name;

　　　　　// 正常
   Function f = name -> "hello" + name;
	
	System.out.println(f.test("Java"));
  }
  
  private static interface Function {
      String test(String name);
  }
}
```
# モジュールシステム
■<font color="red">モジュール化を行うには、必ず`module-info.java`が必要である。</font>

■モジュールの設定は`module-info.java`の中に記述する。

■モジュールの設定では、どのパッケージを公開するかを記述する。（export<font color="red">s</font>で宣言）

■モジュールの設定では、どのモジュールを利用するかを記述する。（require<font color="red">s</font>で宣言）

■モジュールでは、標準で<font color="red">java.base</font>モジュールが標準で組み込まれている。

■利用するモジュールを伝搬するには、requiresの後に、<font color="red">transitive</font>を追記する。

■相互間で利用し合う関係だと、コンパイルエラーを起こす。

■モジュールを実行するときには、モジュールに対してクラスパスが通るので、モジュールに含まれるプログラムはモジュール内のディレクトリにアクセス可能である。
```java
// ※module-info.java内

module モジュール名 {  // {}内に設定を記述
  exports パッケージ名;
  requires モジュール名;
  requires transitive モジュール名;
}

module A { requires B; }  // コンパイルエラー
module B { requires A; }  //　コンパイルエラー
```
## コマンド一覧
`■モジュールを作成する`
→  **jmod**

`■モジュールの設定情報を調べる`
→  **java --describe-module**
→  **jmod describe**

`■module-info.javaでexportされていないパッケージを一時的に利用する。`
→  **javac --add-export**

`■クラス・メソッド・jarファイル・モジュールの依存関係を調べる`
→  **jdeps --list-deps**
→  **java --show-module-resolution**

`■モジュールファイルのコンパイル（-dオプション）`
→  **javac -d クラスファイルの出力先ディレクトリ コンパイルするファイルのパス**
※モジュールのコンパイルは、module-info.java＋その他のソースファイルを一緒にコンパイルする事が基本。

`■モジュールの実行(--module-path -mオプション）`
→  **java --module-path モジュールのルートディレクトリ -m 実行したいモジュールのクラス**