Javaのクラスについて整理してみました



## はじめに
現在、私が進行しているJavaの勉強会でまとめた内容です。

内容に不正確な点があれば、ご指摘いただけるとありがたいです。

https://github.com/whiteship/live-study/issues/5

- 韓国人として、日本語とコンピュータの勉強を同時に行うために、ここに文章を書いています
- 翻訳ツールの助けを借りて書いた文章なので、誤りがあるかもしれません



## 勉強する内容
- クラスを定義する方法
- オブジェクトを作成する方法（`new`キーワードの理解）
- メソッドを定義する方法
- コンストラクタを定義する方法
- `this`キーワードの理解


## クラスとは何でしょうか？
- 現実世界の「オブジェクト」をコードの世界で表現するための設計図です。  
- オブジェクトが持つ属性（フィールド）や機能（メソッド）を定義します

### オブジェクト（インスタンス）とは何でしょうか？
- クラスを基に生成された、メモリ上の実体を指します

## アクセス修飾子について
- クラス（インスタンス）やその属性（フィールド）、機能（メソッド）を理解する前に、以下のようなアクセス修飾子について学ぶ必要があります


| アクセス修飾子 | クラス内 | 同じパッケージ内 | サブクラス | 外部クラス |
|---------------|----------|-----------------|-----------|-----------|
| `public`      | ○        | ○               | ○         | ○         |
| `protected`   | ○        | ○               | ○         | ×         |
| `default`     | ○        | ○               | ×         | ×         |
| `private`     | ○        | ×               | ×         | ×         |

### 使用箇所

| 対象       | `public` | `protected` | `default` | `private` |
|------------|----------|-------------|-----------|-----------|
| クラス     | ○        | ×           | ○         | ×         |
| フィールド | ○        | ○           | ○         | ○         |
| メソッド   | ○        | ○           | ○         | ○         |
| コンストラクタ | ○        | ○           | ○         | ○         |


### アクセス修飾子の説明
- **`public`**: すべてのクラスからアクセス可能です
- **`protected`**: 同じパッケージ内のすべてのクラスおよびサブクラスからアクセス可能です
- **(default) パッケージ・プライベート**: アクセス修飾子を明示しない場合の設定で、同じパッケージ内でのみアクセス可能です
- **`private`**: 同じクラス内でのみアクセス可能であり、他のクラスからはアクセスできません


https://docs.oracle.com/javase/specs/jls/se23/html/jls-6.html#jls-6.6


```java
package example;

public class Example {
    public int publicField = 1;       // どこからでもアクセス可能
    protected int protectedField = 2; // 同じパッケージ内およびサブクラスからアクセス可能
    int defaultField = 3;            // 同じパッケージ内でのみアクセス可能
    private int privateField = 4;    // 同じクラス内でのみアクセス可能

    public Example() {}              // どこからでもインスタンス生成可能
    protected Example(String name) {}// 同じパッケージ内およびサブクラスでインスタンス生成可能
    Example(int value) {}            // 同じパッケージ内でのみインスタンス生成可能
    private Example(boolean flag) {} // 同じクラス内でのみインスタンス生成可能
}
```

### アクセス修飾子はなぜ使うのか？
- **カプセル化**: データの隠蔽とオブジェクト間の相互作用を最小限に抑えるため
- **保守性**: 外部からアクセス可能な範囲を明確に定義することで、コードの安定性を確保するため
- **拡張性**: `protected`を活用し、サブクラスから必要なメンバーのみアクセス可能にすることで柔軟な設計を可能にするため


## クラスを定義する方法

```java
public class Human{
     // クラスの内容 ..
}
```

このようにクラスを定義します。

クラスの中には以下のようなものを定義することができます。

先ほど述べたように、アクセス修飾子を使用してクラスへのアクセスを制限することが可能です。

public: どこからでもアクセス可能

```java
class Human{
 // クラスの内容 ..
}

```
もし次のように定義した場合、同じパッケージ内でのみアクセス可能です。

- **`(default)`**: 同じパッケージ内でのみアクセス可能

その他のキーワードとしては以下のものがあります：

- **`public`**: どこからでもアクセス可能
- **`(default)`**: 同じパッケージ内でのみアクセス可能
- **`final`**: 継承が不可能なクラスとして定義
- **`abstract`**: 抽象クラスとして宣言

これらについての詳細は、次回の記事「継承とパッケージ」で取り上げる予定です。

なお、先ほど述べた `{}` で囲まれた部分（ローカル変数として扱われる範囲）には、インスタンスのライフサイクル中に存在するコードが定義されます。


### ネストクラス (Nested Class)

Javaでは、クラスの中に別のクラスを定義することができます。  
これを **ネストクラス** と呼びます。

```java
public class OuterClass {
    // 静的ネストクラス
    static class StaticNestedClass {
        // 静的ネストクラスの内容
    }
    
    // インナークラス
    class InnerClass {
        // インナークラスの内容
    }
}
```
ネストクラスは、次の2種類に分類されます。

- 静的ネストクラス
- 非静的ネストクラス（インナークラス）

:::note info
- **非静的（non-static）**: **インナークラス（inner class）** と呼ばれます。  
- **静的（static）**: **静的ネストクラス（static nested class）** と呼ばれます
:::

非静的ネストクラスは、囲んでいるクラスの他のメンバー（`private` を含む）にもアクセスすることができます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/f5f03722-a7fb-7559-35ae-f8eb9803b82a.png)

次のようにコードを記述して実行してみると、`privateField` に正常にアクセスし、出力されることを確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/7c521652-708b-64b0-a498-e0b79e651dbd.png)

それが可能な理由は、インナークラスが外部クラスのコンテキスト（Context）を共有しているためです。

上記のコード例にある `OuterClass.java` を `javac` でコンパイルしてみると、次のようになります

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/6e45ce81-8f9d-3b07-2a1c-126fccf93473.png)

`OuterClass$InnerClass.class` と `OuterClass.class` という2つのクラスファイルが生成されることを確認できます。

これら2つのバイトコードを確認すると、次のようになっています（長いため、写真ではなくテキストで記載します）。


```markdown
  ~/Documents/java_study/main ❯ javap -c OuterClass$InnerClass.class                                     at  03:02:34 PM
Compiled from "OuterClass.java"
public class OuterClass {
  public OuterClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #7                  // String Private Field
       7: putfield      #9                  // Field privateField:Ljava/lang/String;
      10: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #10                 // class OuterClass
       3: dup
       4: invokespecial #15                 // Method "<init>":()V
       7: astore_1
       8: new           #16                 // class OuterClass$InnerClass
      11: dup
      12: aload_1
      13: dup
      14: invokestatic  #18                 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
      17: pop
      18: invokespecial #24                 // Method OuterClass$InnerClass."<init>":(LOuterClass;)V
      21: astore_2
      22: aload_2
      23: invokevirtual #27                 // Method OuterClass$InnerClass.printPrivateField:()V
      26: return
}

  ~/Documents/java_study/main ❯ javap -c OuterClass.class                                                at  03:02:43 PM
Compiled from "OuterClass.java"
public class OuterClass {
  public OuterClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: aload_0
       5: ldc           #7                  // String Private Field
       7: putfield      #9                  // Field privateField:Ljava/lang/String;
      10: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #10                 // class OuterClass
       3: dup
       4: invokespecial #15                 // Method "<init>":()V
       7: astore_1
       8: new           #16                 // class OuterClass$InnerClass
      11: dup
      12: aload_1
      13: dup
      14: invokestatic  #18                 // Method java/util/Objects.requireNonNull:(Ljava/lang/Object;)Ljava/lang/Object;
      17: pop
      18: invokespecial #24                 // Method OuterClass$InnerClass."<init>":(LOuterClass;)V
      21: astore_2
      22: aload_2
      23: invokevirtual #27                 // Method OuterClass$InnerClass.printPrivateField:()V
      26: return
}
```

上記のバイトコードを見ると、`OuterClass` は内部クラス（`OuterClass$InnerClass`）を明示的に参照していることが分かります。

また、`main` メソッドには内部クラスのインスタンスを生成し、そのメソッドを呼び出している部分が含まれています。

```markdown
8: new           #16                 // class OuterClass$InnerClass
...
23: invokevirtual #27                 // Method OuterClass$InnerClass.printPrivateField:()V
```
一方、内部クラスは常に自分の外部クラスに依存しています。

`OuterClass$InnerClass` を確認すると、外部クラスのインスタンスを参照していることが分かります。

```markdown
invokespecial #24                 // Method OuterClass$InnerClass."<init>":(LOuterClass;)V
```

さらに、内部クラスが外部クラスの `private` フィールドやメソッドにアクセスできることも確認できます。


```markdown
getfield      #9                  // Field OuterClass.privateField:Ljava/lang/String;
```

:::note info
### バイトコードから分かること
- 内部クラスは必ず外部クラスの参照を必要とします
- 外部クラスなしでは、内部クラス単独で動作することはできません
- 内部クラスは外部クラスの `private` フィールドやメソッドにアクセスできます
:::

### ネストクラスを使用する理由

1. **論理的に一箇所でのみ使用されるクラスをグループ化する方法**:
    - もしあるクラスが他の特定のクラスでのみ有用である場合、そのクラスを対象のクラス内に含め、両者を一緒に維持することが理にかなっています。
    - このような **ヘルパークラス（helper class）** をネストすることで、パッケージがより簡潔になります。

2. **カプセル化を向上させる**:
    - 2つのトップレベルクラス A と B を考えてみましょう。B が本来 `private` として宣言されるべき A のメンバーにアクセスする必要がある場合、B を A 内に隠すことで、A のメンバーを `private` に保ちながらも B がアクセスできるようになります
    - また、B 自体も外部から隠すことが可能です

    ```java
    public class A {
        private String privateFiled = "haroya";

        public class B {
            public void printPrivateFiled() {
                System.out.printlnf("print : " + privateFiled);
            }
        }

     public static void main(String[] args) {
        A a = new A();
        A.B b = a.new B();
        b.printPrivateFiled(); // Aの private メンバーにアクセス
    }
    ```
3. **コードの可読性と保守性を向上させる**:
   トップレベルクラス内に小さなクラスをネストすることで、そのコードが使用される場所により近くなり、可読性と保守性が向上します

https://docs.oracle.com/javase/tutorial/java/javaOO/nested.html

https://docs.oracle.com/javase/tutorial/java/javaOO/innerclasses.html

### ローカルクラス

Javaでは、メソッド、コンストラクタ、またはブロックの内部でもクラスを定義することができます。

これらはそのローカルスコープ（`{ }` 内部）でのみ使用可能で、メソッドのローカル変数のように動作します。

以下はその例として作成したコードです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/ab54730e-361c-a171-b9d0-b1f8e9287a42.png)

```java
public void sayHello() {
        class HelloWorld {
            void printMessage() {
                System.out.println("Hello, World!");
            }
        }

        HelloWorld hello = new HelloWorld();
        hello.printMessage();
    }
```
コードをご覧いただくと、次のように `sayHello()` メソッド内で `class HelloWorld` を定義していることが分かります。

これを **ローカルクラス** と呼びます。

バイトコードで分析すると、次のようなことが分かります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/18b3a601-69ab-1876-95ed-9630c9edd978.png)

以前のネストクラスと同様に、クラスファイルが2つ生成されましたが、


```markdown
  ~/Documents/java_study/main ❯ javap -c Haroya.class                                                                            at  03:37:38 PM
Compiled from "Haroya.java"
public class Haroya {
  public Haroya();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public void sayHello();
    Code:
       0: new           #7                  // class Haroya$1HelloWorld
       3: dup
       4: aload_0
       5: invokespecial #9                  // Method Haroya$1HelloWorld."<init>":(LHaroya;)V
       8: astore_1
       9: aload_1
      10: invokevirtual #12                 // Method Haroya$1HelloWorld.printMessage:()V
      13: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #15                 // class Haroya
       3: dup
       4: invokespecial #17                 // Method "<init>":()V
       7: astore_1
       8: aload_1
       9: invokevirtual #18                 // Method sayHello:()V
      12: return
}

  ~/Documents/java_study/main ❯ javap -c Haroya\$1HelloWorld                                                                     at  03:37:50 PM
Compiled from "Haroya.java"
class Haroya$1HelloWorld {
  final Haroya this$0;

  Haroya$1HelloWorld(Haroya);
    Code:
       0: aload_0
       1: aload_1
       2: putfield      #1                  // Field this$0:LHaroya;
       5: aload_0
       6: invokespecial #7                  // Method java/lang/Object."<init>":()V
       9: return

  void printMessage();
    Code:
       0: getstatic     #13                 // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #19                 // String Hello, World!
       5: invokevirtual #21                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return
}
```
`.class` ファイルは次のように生成されることを確認できます。

以前と同様にクラスごとにファイルが生成されましたが、ローカルクラスのファイルを詳しく見ると、


```markdown
final Haroya this$0;

  Haroya$1HelloWorld(Haroya);
    Code:
       0: aload_0
       1: aload_1

```
外部クラスの参照がコンストラクタに含まれており、  
`javac` コンパイラがローカルクラスの安全性を保証するために、  
`final Haroya this$0;` が宣言されていることを確認できます。

これを要約すると以下の通りです

### Inner ClassとLocal Classの違い

**Inner Class（内部クラス）**
- 外部クラスの情報を暗黙的に把握しています。
    - 内部クラスは外部クラスのすべてのメンバー（`private` を含む）に直接アクセス可能です。
    - 外部クラスのインスタンスを明示的に参照しなくても、外部クラスのメンバーにアクセスできます。

**Local Class（ローカルクラス）**
- 外部クラスの参照を明示的に保存します。
    - ローカルクラスは `this$0` フィールドを通じて外部クラスの情報に間接的にアクセスします。
        - 外部クラスの参照をコンストラクタの引数のように受け取り、利用します。
    - 定義されたブロック内のローカル変数や引数をキャプチャして使用します（ただし、それらは `final` または「事実上の`final`」である必要があります）。


### Effectively Finalとは？
Java 8で導入された概念で、変数が明示的に `final` として宣言されていなくても、初期化後に値が変更されない変数を指します。

```java
void satHello(){
    String hello = "こんにちは";
    hello = "안녕하세요";
}
```

次のように値が変更される場合、`final` ではありません。

```java
void satHello(){
    String hello = "こんにちは";
}
```
以下のようなコードでは、ローカル変数のスコープ内で `hello` が一度値を割り当てられ、その後スコープが終了するまで変更されないことが確認できます。

これを実質的な `final`、すなわち **Effectively Final** と呼びます。

```java
public class Haroya {
    public void sayHello() {
        String hello = "こんにちは";
        class HelloWorld {
            void printMessage() {
                System.out.println(hello);
            }
        }

        HelloWorld helloworld = new HelloWorld();
        helloworld.printMessage();
    }

    public static void main(String[] args) {
        Haroya haroya = new Haroya();
        haroya.sayHello();
    }
}
```

以前に作成したローカルクラスのコードを少し修正した例は以下の通りです。

`hello` という変数は、`sayHello()` メソッド内で値が割り当てられ、

```java
public void sayHello() {
        String hello = "こんにちは";
```

 ```java
 class HelloWorld {
            void printMessage() {
                System.out.println(hello);
            }
        }
```
ローカルクラスでは、一度も値の変更が行われませんでした。

この状態を **実質的な `final` 状態（Effectively Final）** と呼ぶことができます。

では、このコードを次のように変更した場合はどうなるでしょうか？


```java
 class HelloWorld {
            void printMessage() {
                hello = "안녕하세요";
                System.out.println(hello);
            }
        }
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/6735f704-089d-5ae5-8ecc-65f9b20aa34f.png)

もし次のように内部で値を変更した場合、


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/100dcbf4-55d6-47cd-b574-e34d4048c3f0.png)


次のようなエラーが発生します。

なぜなら、以前説明したように、オブジェクトの参照をコピーして使用しているためです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/60d21e2d-8a4d-4fb5-2686-cd04725fa052.png)

スタック内のメソッドは命令が終了するとライフサイクルに従って消えますが、  
ヒープメモリに生成されたオブジェクトはGC（ガベージコレクション）が実行されるまで再利用可能です。

例えば、複数のスレッドを生成してヒープ上のオブジェクトを参照する場合、  
その変数が `final` でないと値が変更され続けるため、オブジェクトの整合性を保証できません。  
そのため、Javaでは `final` を使用して値をコピーする方法が採用されています。


以下のコードは、`ThreadExample` クラスの例で、ローカル変数がスレッド間で共有される状況を示しています。

```java
public class ThreadExample {
    public void method() {
        String message = "こんにちは";  // スタック上のローカル変数

        // 1. 最初のスレッド
        new Thread(() -> {
            // message がヒープにコピーされて保存される
            System.out.println("スレッド1: " + message);
        }).start();

        // 2. 二番目のスレッド
        new Thread(() -> {
            // 同じ message を使用
            System.out.println("スレッド2: " + message);
        }).start();

        // メソッドが終了してもスレッドは実行を継続する！
    }
}
```

上記の例のようなコードは許容されますが、ローカルスコープ（`{}`）内で値を変更しようとすると、


```java
    new Thread(() -> {
        System.out.println("スレッド1 " + message);
        message = "안녕하세요";
    }).start();
```

2番目のスレッドでは、`message` の一貫性を保証することができません。

このような理由から、Javaでは **Effectively Final** という概念が導入されています。

### 匿名クラス（Anonymous Class）

```java
interface Printable {
    void print();
}

class OuterClass {
    void method() {
        // インターフェースやクラスをその場で実装
        Printable printable = new Printable() {
            public void print() {
                System.out.println("匿名クラス");
            }
        };
        
        printable.print();
    }
}
```

このように、Javaでは匿名クラスが導入されています。

匿名クラスは **Innerクラス** の一種であり、  
一度だけ使用するオブジェクトを簡単に生成・破棄することで、  
コードの保守性を向上させる役割を担っています。


https://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html

## その他の継承に関する内容...
```java
class Human extends Animal implements HumanInterface{}
```
このように、スーパークラスやインターフェースから情報を継承することができます。
これについては、次回の記事で「継承」について詳しく説明する際に記載する予定です。

## 属性（フィールド）

- **インスタンス変数**: オブジェクトごとに個別に生成される

```java
public class Person {
    private String name;           // インスタンス変数
    private int age;               // インスタンス変数
    private final String id;       // 定数（final）のインスタンス変数
    private transient String secret; // シリアライズ対象外のフィールド
}


```
- **静的（static）変数**: クラスごとに1つ生成され、すべてのオブジェクトで共有される

```java
private static int count = 0;
```

:::note info
### 静的（static）変数  
すべてのオブジェクトが共有するとはどういう意味でしょうか？

```java
public class Test {

    private static int count = 0;

    public Test() {
        count++;
    }
    
    public int getCount() {
        return count;
    }
}
```
次のように定義した場合、

```java
public class Main {
    public static void main(String[] args) {
        Test test1 = new Test();
        Test test2 = new Test();
        System.out.println("test1 : " + test1.getCount());
        System.out.println("test2 : " + test2.getCount());
    }
}
```
以下のコードを呼び出すと、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/b35217ac-de18-b31b-7301-e271a546f2a2.png)


どちらの場合も、`count` は2と出力されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/bba6d13d-4f7d-0835-3b91-a1e0b4803036.png)

Testクラスのバイトコードを見ると、`getStatic` や `putStatic` という記述が出てきますが、  
JVM標準文書を検索してみると、より詳しい情報を得ることができました。

`getStatic` を例に取ると、静的（static）フィールドを取得してスタックにプッシュする命令と記載されていました。

なぜなら、JVM内で Method Area に静的変数（static フィールド）が既に保存されているため、  
クラスレベルでメモリに一つだけ存在し、その値を取得してスタック（Javaの命令実行、Javaはスタックベース）に載せるためです。

要約すると、JVMの Method Area に静的（static）フィールドが保存されているため、  
クラスレベルで一つだけ存在し、必要に応じてスタックに載せて使用されるということです。
:::

https://docs.oracle.com/javase/specs/jvms/se21/html/jvms-6.html

### フィールドに関する整理

- **Method Area（Static Area）**  
    - `static` メンバーが保存される領域  
    - プログラム開始時に生成され、終了時に破棄される  
    - すべてのスレッドで共有される  
    - `static` 変数、`static` メソッド、クラス情報などが保存される  

- **Heap**  
    - インスタンス（オブジェクト）が保存される領域  
    - `new` 演算子で生成されたオブジェクトやインスタンス変数が保存される  
    - GC（ガベージコレクション）の対象  


## メソッド

メソッドは次のように定義します。

```java
public void printHello() {
    System.out.println("hello");
}
```
- **静的（static）メソッド**  
    - 静的メソッドは、先ほどの `static` フィールドと同様にメソッド領域にロードされます。  
    - 通常のインスタンスメソッドとの違いは、**クラス**に結びついているため、クラスインスタンスとは関係なく呼び出すことができる点です。  

```java
public class Test {

    private static int count = 0;

    public static int getCount() {
        return ++count;
    }
}
```
次のように定義して、
```java
public class Main {
    public static void main(String[] args) {
        System.out.println("no instance 1 : " + Test.getCount());
        System.out.println("no instance 2 : " + Test.getCount());
    }
}
```

次のようにインスタンスを生成せずにコードを実行すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/0c576c0a-499d-dbe7-258c-82b43104ce07.png)
正常に呼び出されることを確認できます。

:::note alert
**静的メソッドがインスタンスフィールドにアクセスできない理由は？**
```java
package org.example;

public class Test {

    private int count = 0;

    public static int getCount() {
        return ++count;
    }
}
```
次のように、インスタンスフィールドである `private int count = 0;` に、`static getCount()` はアクセスできません。

その理由は、静的（static）メソッドは Method Area にあるクラスを直接呼び出すのに対し、  
インスタンスフィールドは特定のインスタンス（Heap）で生成されるためです。

```java
error: non-static variable count cannot be referenced from a static context
        return ++count;
                 ^
```

実行してみると、次のようなコンパイルエラーが発生することを確認できます。
:::


## 初期化ブロック

- **インスタンス初期化ブロック**  
    - オブジェクトが生成されるたびに実行されるブロック  
    - コンストラクタよりも優先して実行されます  

```java
public class Test {

    private static int count = 0;

    {
        count += 1;
        System.out.println("instance block");
    }

    public int getCount() {
        return count;
    }
}
```
次のように `{ }` 内で宣言することができます。

```java
public class Main {
    public static void main(String[] args) {
       Test test1 = new Test();
         System.out.println(test1.getCount());
       Test test2 = new Test();
       System.out.println(test2.getCount());
    }
}
```
다음과 같은 코드를 실행한다면

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/ad363ba1-4e16-dfc8-f8d3-8205b0907482.png)
次のようなコードを実行すると、`{ }` が正しく適用されることを確認できます。

:::note info
**「コンストラクタを使えば良いのでは？」**  
そうではありません。共通の処理が含まれる場合、`{ }` を使用することでボイラープレートコードを削減できます。

```java
public class Test {

    private int count;

    {
        count = 0;
        System.out.println("count = " + count);
    }

    public Test() {
        count++;
    }

    public Test(int count) {
        this.count = count;
    }

    public int getCount() {
        return count;
    }

}

```

次のように、インスタンスを `0` に初期化してからコンストラクタを呼び出し、  
その後に出力するロジックを作成しました。


```java
public class Main {
    public static void main(String[] args) {
       Test test1 = new Test();
       System.out.println(test1.getCount());
       Test test2 = new Test(100);
       System.out.println(test2.getCount());
    }
}
```

このコードを記述して実行した結果が以下の通りです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/163e8a27-bc16-c7f3-9f59-6a18668d3df2.png)
共通の処理がインスタンス初期化ブロックを経由することが分かります。  

共通のコンストラクタ呼び出し前のロジックは、インスタンス初期化ブロックに移しても問題ありません。
:::

- **静的初期化ブロック（static block）**  
    - クラスが最初にロードされる際に一度だけ実行される初期化ブロックです。
```java
package org.example;

public class Test {

    private static int count;

    static {
        count = 0;
        System.out.println("count = " + count);
    }
    
    public int getCount() {
        return ++count;
    }

}

```

次のように、`static` で囲まれた `{ }` 初期化ブロックを記述します。


```Java
public class Main {
    public static void main(String[] args) {
       Test test1 = new Test();
       System.out.println(test1.getCount());
       Test test2 = new Test();
       System.out.println(test2.getCount());
    }
}
```
次のようなコードを実行すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/22098899-a0fa-7dab-e687-a1ce737e58c8.png)

クラスがロードされる際に、必要な初期化処理が一度だけ実行されることを確認できます。

:::note info
**静的ブロックはシングルトンパターンを使用する際に応用できます。**

```java
public class Singleton {
    private static final Singleton instance;

    // 静的ブロックで初期化
    static {
        try {
            instance = new Singleton();
        } catch (Exception e) {
            throw new RuntimeException();
        }
    }

    // private コンストラクタ
    private Singleton() {
        // 初期化作業
    }

    public static Singleton getInstance() {
        return instance;
    }
}

```
:::

## コンストラクタ

コンストラクタとは、インスタンスを生成し初期化する際に使用する特殊なメソッドです。

- クラス名と同じ名前を持ち、戻り値の型がありません

```java
package org.example;

public class Test {
    private int count;

    public Test(){
        count = 0;
    }
}

```

- コンストラクタとメソッドは **`Overloading`（オーバーローディング）** が可能です

```java
package org.example;

public class Test {
    private int count;

   public Test(){
         count = 0;
   }
   
   public Test(int count){
         this.count = count;
   }

}

```

- コンストラクタを明示しない場合、デフォルトコンストラクタが自動的に追加されます（`javac` のコンパイル時に）


```java
public class Test {}

```
次のようにコンストラクタのないクラスを記述し、バイトコードを確認してみたところ、


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/beca3c60-74be-997c-0f82-54e5068077cd.png)


次のように、`public org.example.Test()` という引数のないデフォルトコンストラクタが  
`javac` コンパイラによって追加されていることを確認できます。

### Super

以前のデフォルトコンストラクタのみを持つ `Test.class` のバイトコードを確認すると、  
次のようなコードが含まれていることが分かります。

```markdown
 1: invokespecial #1                  // Method java/lang/Object."<init>":()V
```
すべてのクラスは `Object` を親として持ち、すべてのコンストラクタは定数プールに保存されている親クラスのコンストラクタを呼び出します。  
言い換えると、`super();` が内部的に隠されています。

`super();` に関しては、次回の継承についての記事で整理する予定です。


https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-6.html#jvms-6.5.invokespecial

## オブジェクトを作成する方法（`new` キーワードの理解）

`new` キーワードは、次のようにオブジェクト（クラス）のコンストラクタを呼び出して使用します。

```java
Test test = new Test();
``` 

- new はヒープメモリにオブジェクト用の領域を割り当てます。

- 宣言されているが初期化されていない値は、javac コンパイラによって次のように値が割り当てられます。
 
| Data Type         | Default Value (for fields) |
|-------------------|----------------------------|
| `byte`            | `0`                        |
| `short`           | `0`                        |
| `int`             | `0`                        |
| `long`            | `0L`                       |
| `float`           | `0.0f`                     |
| `double`          | `0.0d`                     |
| `char`            | `'\u0000'`                 |
| `String` (or any object) | `null`             |
| `boolean`         | `false`                    |

https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html


## `this` キーワードの理解

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/b2abd23f-24a6-5c18-190b-fb5b3631f99d.png)

> The Java Virtual Machine uses local variables to pass parameters on method invocation. On class method invocation, any parameters are passed in consecutive local variables starting from local variable 0. On instance method invocation, local variable 0 is always used to pass a reference to the object on which the instance method is being invoked (this in the Java programming language). Any parameters are subsequently passed in consecutive local variables starting from local variable 1.

- Java仮想マシン（JVM）は、メソッドを呼び出す際にローカル変数を使用してパラメータを渡します。  
  クラスメソッドを呼び出す場合、すべてのパラメータは0番目のローカル変数から順に連続して格納されます。  
  インスタンスメソッドを呼び出す場合、常に0番目のローカル変数には、呼び出しているオブジェクトの参照（Javaでは`this`）が格納されます。  
  その後、パラメータは1番目のローカル変数から順に格納されます


https://docs.oracle.com/javase/specs/jvms/se23/html/jvms-2.html#jvms-2.6.1

Javaのインスタンスメソッドやコンストラクタでは、スタックに参照を載せるための `this` が含まれています。



```java
package org.example;

public class Test {

    private static int staticInt = 0;

    private int instanceInt = 0;

    public static void staticMethod() {
        ++staticInt;
    }

    public void instanceMethod() {
        ++instanceInt;
    }

}
```

バイトコードを確認すると、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/76056c4f-17bf-1fc5-061c-e9afa1bf7ec2.png)

このようになっています。確認すると、静的メソッドやインスタンスには、

```markdown
0: aload_0
```
次のような命令が必ず実行されることを確認できます。  
これが `this` に対応するバイトコードで、その役割は以下の通りです。

> インスタンスメソッドを呼び出す場合、常に0番目のローカル変数には、呼び出しているオブジェクトの参照（Javaでは`this`）が格納されます。

- **オブジェクトの参照をスタックにロードする際に`this`を使用します。**  
- **インスタンスメソッドは、インスタンスフィールドや他のインスタンスメソッドにアクセスする際、`this`を通じてスタックにロードします。**

デフォルトコンストラクタの場合、以前説明したように親クラスのメソッド（`Object` のコンストラクタ）を呼び出すため、  
`this` の参照をスタックにロードします。

ただし、JVMでは `this` を自動的に呼び出すため、


```java
public class Test {

    private int num = 0;

    public Test(int a) {
        // this が隠れている
        // super も隠れている
        num = a;
    }
}
```

次のように代入されます。


```markdown
public static void staticMethod();
    Code:
       0: getstatic     #13                 // Field staticInt:I
       3: iconst_1
       4: iadd
       5: putstatic     #13                 // Field staticInt:I
       8: return
```

一方で、`static` メソッドでは `this` を介して呼び出すことはありません。  
なぜなら、`static` メソッドは既に JVMランタイムの Method Area にロードされており、  
スタックにロードする必要がないためです。


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/1d9079e5-b4a8-0217-b97f-380001abefae.png)

公式ドキュメントを参照すると、次のように記載されています：

> A method that is declared static is called a class method.  
> クラスメソッドは特定のオブジェクトへの参照なしに常に呼び出されます。

- `static` と宣言されたメソッドは特定のオブジェクトとは関連せず、クラス自体に属するメソッドです。
- そのため、オブジェクトを作成せずとも直接呼び出すことができます

> static メソッド内では `this` や `super` のようなキーワードは使用できません。  
> なぜなら、これらのキーワードは特定のオブジェクト（現在のオブジェクト）を指すものですが、static メソッドはオブジェクトなしで呼び出されるためです。

---

改めて定義すると、`this` とは以下の通りです：

- `this` は参照をスタックにロードするために使用されます

:::note info
JVMのメソッド呼び出し規約によれば、インスタンスメソッドでは最初のローカル変数スロットに `this` が格納されます。  
スタックに `this` をロードすることで、メソッドがオブジェクトの状態に基づいて動作することを可能にしています。  
インスタンスメソッドのバイトコード実行時に最初の命令として `aload_0` によって `this` をスタックに載せるのも、この規約によるものです。
:::

- 内部オブジェクトが存在せず、内部インスタンスにアクセスする必要がない場合、`javac` コンパイラでは `this` が生成されません。 
（例: オブジェクト参照をスタックにロードする必要がない状況）



```java
public class Test {

    public void print() {
        System.out.println("Hello World");
    }
}
```

次のように定義した場合（内部でアクセスするインスタンスフィールドが存在しない場合）、

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3815412/f77cdd76-a2e5-7d61-74a5-bc261b3a3cea.png)

`String` は定数プールに格納され、命令は Method Area から取得されるため、  
内部インスタンスを参照する必要がありません。  
そのため、`aload_0`（`this`）が生成されません。

https://docs.oracle.com/javase/specs/jls/se23/html/jls-15.html#jls-15.8

その他、`this` キーワードを直接参照が必要な箇所で以下のように使用することができます。

1. 自分自身を明確にする場合
```java
public class Test {
    private int count;

    public Test(int count) {
        this.count = count; 
        //    this.count = count; 
        // this.count はインスタンス変数、count は引数
    }
}
```
:::note info
int count は重複宣言ではありませんか？
ローカル変数についてもう一度確認しましょう。 
:::

.2. 自分のインスタンスを参照する場合

```java
public Test increment() {
    this.count++;
    return this; // 現在のオブジェクトを返す
}
```

### コンストラクタチェイニング

- コンストラクタは特別なメソッドであり、メソッドのようにオーバーロードをサポートします。  
- `this` は自分自身のインスタンスを参照するときに使用されます。  

これらの2つの特性を利用して、コンストラクタが自分自身の別のコンストラクタを呼び出すことができます。  
これを **コンストラクタチェイニング** と呼びます。

```java
public class コンストラクタチェイニング {
    private int count;
    private String name;

    // デフォルトコンストラクタ
    public コンストラクタチェイニング() {
        this(0, "default"); // 別のコンストラクタを呼び出し
    }

    // 引数が1つのコンストラクタ
    public コンストラクタチェイニング(int count) {
        this(count, "default"); // 別のコンストラクタを呼び出し
    }

    // 引数が2つのコンストラクタ
    public コンストラクタチェイニング(int count, String name) {
        this.count = count;
        this.name = name;
    }
}
```

### メソッドチェイニング

次のように、メソッドチェイニングも可能です。

```java
public class Person {
    private String name;
    private int age;

    public Person setName(String name) {
        this.name = name;
        return this;  // 現在のインスタンスを返すことでメソッドチェイニングが可能    
        }

    public Person setAge(int age) {
        this.age = age;
        return this; // 現在のインスタンスを返すことでメソッドチェイニングが可能
    }
}

// 使用例
Person person = new Person().setName("Alice").setAge(25);

```
これ以外にも、ラムダ式や動的プロキシのような場面でも使用することができます。

重要な点は、インスタンスの参照をスタックにロードする必要がある場合、
JVMが自動的に追加するか、直接呼び出して使用すればよいということです。


:::note info
**メソッドチェイニングの例「ビルダーパターン」**

Lombokの `@Builder` アノテーションを付けたコードのバイトコードを展開すると、  
次のようにビルダーパターンを活用していることが分かります。

メソッドチェイニングを活用してビルダーパターンを実現していることが確認できます。


```java
public Member(final Long id, final String nickName, final String email, final String profileImageUrl, final LocalDateTime lastLoginAt) {
        this.id = id;
        this.nickName = nickName;
        this.email = email;
        this.profileImageUrl = profileImageUrl;
        this.lastLoginAt = lastLoginAt;
    }

    public static class MemberBuilder {
        private Long id;
        private String nickName;
        private String email;
        private String profileImageUrl;
        private LocalDateTime lastLoginAt;

        MemberBuilder() {
        }

        public MemberBuilder id(final Long id) {
            this.id = id;
            return this;
        }

        public MemberBuilder nickName(final String nickName) {
            this.nickName = nickName;
            return this;
        }

        public MemberBuilder email(final String email) {
            this.email = email;
            return this;
        }

        public MemberBuilder profileImageUrl(final String profileImageUrl) {
            this.profileImageUrl = profileImageUrl;
            return this;
        }

        public MemberBuilder lastLoginAt(final LocalDateTime lastLoginAt) {
            this.lastLoginAt = lastLoginAt;
            return this;
        }

        public Member build() {
            return new Member(this.id, this.nickName, this.email, this.profileImageUrl, this.lastLoginAt);
        }

        public String toString() {
            return "Member.MemberBuilder(id=" + this.id + ", nickName=" + this.nickName + ", email=" + this.email + ", profileImageUrl=" + this.profileImageUrl + ", lastLoginAt=" + this.lastLoginAt + ")";
        }
    }
```
:::


次のように、チェイニングを通じてビルダーパターンを実現していることが分かります。

## 参考文献  
一部の簡単なサンプルコードはChatGPTを使用しました。  
誤った内容や文法の間違いがありましたら、フィードバックをいただけると幸いです。