コンストラクタ　Java

はじめに
--
インフラの分野でも、Iac化が進んで行くと考えています。そこで、ノウハウが体系だっているものが学び易いと考えて、Javaを学びはじめました。

今回は、**コンストラクタ** にフォーカスしました。


## コンストラクタの特徴

Javaにおける**コンストラクタ**は、クラスのインスタンス（オブジェクト）を生成するときに呼ばれる特別なメソッド。コンストラクタは、オブジェクトの初期化を行うために使用される。

- コンストラクタは、オブジェクトを初期化するための特別なメソッド。
- 引数なしと引数付きのコンストラクタをオーバーロードして使うことができる。
- `this` キーワードを使って、インスタンス変数と引数を区別できる。

1. **クラス名と同じ名前**を持つ。
2. 戻り値の型（`void`も含む）を持たない。
3. オブジェクトが生成される際に、自動的に呼ばれる。
4. 引数を持たないコンストラクタを「デフォルトコンストラクタ」と呼び、引数を持つコンストラクタを「引数付きコンストラクタ」と呼ぶ。

### コンストラクタの基本的な例

```java
class Car {
    String model;
    int year;

    // 引数なしのコンストラクタ
    public Car() {
        model = "Unknown";
        year = 2020;
    }

    // 引数付きのコンストラクタ
    public Car(String model, int year) {
        this.model = model;
        this.year = year;
    }

    // メソッドで情報を表示
    public void displayInfo() {
        System.out.println("Model: " + model);
        System.out.println("Year: " + year);
    }

    public static void main(String[] args) {
        // 引数なしコンストラクタを使ってオブジェクトを生成
        Car car1 = new Car();
        car1.displayInfo();

        // 引数付きコンストラクタを使ってオブジェクトを生成
        Car car2 = new Car("Tesla", 2023);
        car2.displayInfo();
    }
}
```

### コンストラクタの種類

1. **デフォルトコンストラクタ**（引数なしコンストラクタ）
   - 明示的に定義しない場合でも、Javaが自動的に提供。
   - クラス内で引数付きのコンストラクタを定義すると、デフォルトコンストラクタは提供されない。

2. **引数付きコンストラクタ**
   - インスタンスを生成するときに、必要な初期値を設定するために使用される。

## コンストラクタのオーバーロード

複数のコンストラクタを定義することを「コンストラクタのオーバーロード」と呼ぶ。同じクラス内に引数の数や型が異なる複数のコンストラクタを定義することができる。

```java
class Rectangle {
    int width, height;

    // 引数なしのコンストラクタ
    public Rectangle() {
        width = 1;
        height = 1;
    }

    // 引数付きのコンストラクタ
    public Rectangle(int width, int height) {
        this.width = width;
        this.height = height;
    }

    // 面積を計算するメソッド
    public int getArea() {
        return width * height;
    }

    public static void main(String[] args) {
        // 引数なしのコンストラクタ
        Rectangle rect1 = new Rectangle();
        System.out.println("Area: " + rect1.getArea());

        // 引数付きのコンストラクタ
        Rectangle rect2 = new Rectangle(5, 7);
        System.out.println("Area: " + rect2.getArea());
    }
}
```

## `this` キーワード

コンストラクタ内で、`this` キーワードを使って現在のインスタンスを指すことができる。例えば、引数名とインスタンス変数名が同じ場合、`this`を使って区別することができる。

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

    public Person(String name, int age) {
        this.name = name; // 引数のnameをインスタンス変数nameに代入
        this.age = age;   // 引数のageをインスタンス変数ageに代入
    }

    public void displayInfo() {
        System.out.println("Name: " + name + ", Age: " + age);
    }

    public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        person.displayInfo();
    }
}
```

`this` キーワードを使ってインスタンス変数と引数を区別できる理由

### 背景

Javaでは、メソッドやコンストラクタ内で変数を使う際に、インスタンス変数（クラスのフィールド）と引数（ローカル変数）が同じ名前であると、**名前の衝突**が発生します。その場合、ローカル変数（引数）が優先され、インスタンス変数にはアクセスできません。

このような場合に、`this` キーワードを使うことで、インスタンス変数を明示的に参照することができます。

- `this` キーワードは、現在のインスタンスを参照。
- 引数とインスタンス変数の名前が同じ場合、`this` を使ってインスタンス変数にアクセス。
- `this` はインスタンス変数を明示的に指すため、引数の名前と区別しやすくなる。

```java
class Person {
    String name; // インスタンス変数
    int age;     // インスタンス変数

    // コンストラクタの引数とインスタンス変数が同じ名前
    public Person(String name, int age) {
        // 引数のnameとインスタンス変数nameが同じ名前
        this.name = name; // 引数nameをインスタンス変数nameに代入
        this.age = age;    // 引数ageをインスタンス変数ageに代入
    }

    public void displayInfo() {
        System.out.println("Name: " + name + ", Age: " + age);
    }

    public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        person.displayInfo(); // 出力: Name: Alice, Age: 30
    }
}
```


- **インスタンス変数**
クラスのフィールドとして定義されている変数。ここでは `name` と `age` がインスタンス変数。
- **引数**
メソッドやコンストラクタに渡される値。コンストラクタ `Person(String name, int age)` の引数として `name` と `age` 。

#### `this` キーワードの役割

`this` は、現在のオブジェクトを指す参照。これを使うことで、コンストラクタやメソッド内で**インスタンス変数**を明示的に参照できる。


```java
this.name = name; // 引数nameをインスタンス変数nameに代入
```

- 左辺の `this.name` は、**インスタンス変数** `name` を指しています。
- 右辺の `name` は、**コンストラクタの引数** `name` を指しています。

`this` を使わなければ、`name` だけではローカル変数（引数）を指すことになり、インスタンス変数を変更することができません。

### `this` を使わないとどうなるか？

`this` を使わない場合、コンストラクタ内で引数の名前とインスタンス変数の名前が同じだと、コンパイラは引数を優先し、インスタンス変数にはアクセスできません。例えば次のようになります。

```java
class Person {
    String name; // インスタンス変数
    int age;     // インスタンス変数

    // コンストラクタの引数とインスタンス変数が同じ名前
    public Person(String name, int age) {
        name = name; // これは引数nameを自身に代入しているだけ
        age = age;    // 同様に、引数ageを自身に代入しているだけ
    }

    public void displayInfo() {
        System.out.println("Name: " + name + ", Age: " + age);
    }

    public static void main(String[] args) {
        Person person = new Person("Alice", 30);
        person.displayInfo(); // 出力: Name: null, Age: 0
    }
}
```

この場合、`name = name;` や `age = age;` は、**自分自身に代入**しているだけで、インスタンス変数の値を更新していません。結果的に、インスタンス変数 `name` と `age` は初期値（`null` と `0`）のままです。