インスタンス化時のコンストラクタの呼び出しについて

###■　コンストラクタについて
コンストラクタとは、インスタンス化時に自動的に呼び出される特別なメソッドで、呼び出しと同時にフィールドに初期値を設定する一般的な方法

【Humanクラス】

```Java
public class Human {
    String name = "未設定";
    int age;
    String address;
    int hp = 100;

    public void greet() {
        hp = hp - 10;
        System.out.print("My name is " + name + ".");
        System.out.print("I'm " + age + " years old.");
        System.out.print("I live in " + address + ". ");
        System.out.println("Current HP is " + hp + ".");
    }

}
```

【mainメソッドのクラス】

```Java
public static void main(String[] args) {
        Human h1 = new Human();
        h1.name = "Tanaka";
        h1.age = 25; 
        h1.address = "Tokyo";
        h1.hp = 100;
        h1.greet();

        Human h2 = new Human();
        h2.name = "Yamada";
        h2.age = 28;
        h2.address = "Kanagawa";
        h2.hp = 130;
        h2.greet();
```

上記のようにコンストラクタを利用しない（初期値を設定しない）と、インスタンス化されるすべてオブジェクト毎に再代入する必要が出てくる
※初期値を設定していない場合、値が入っていないわけではなく、String型はNull、int型は0がデフォルトで設定される（boolean：false、配列型：Null）

コンストラクタはインスタンス化時に自動的に呼び出され、各フィールドに初期値が設定される
引数を持たせることでそれぞれのインスタンス化時に値を設定できる

コンストラクタの記述方法は
1．コンストラクタ名はクラス名と同じ
2．戻り値は(void)も記述しない
⇒戻り値を記述すると普通のメソッドとして認識され、エラーも出ない

以下、まずは引数なしのコンストラクタ

【Humanクラス】

```Java
public class Human {

    String name;
    int age;
    String address;
    int hp;
    
    //コンストラクタ
    public Human() {
        name = "未設定";
        address = "未設定";
        hp = 100;
    }

    public void greet() {
        hp = hp - 10;
        System.out.print("My name is " + name + ".");
        System.out.print("I'm " + age + " years old.");
        System.out.print("I live in " + address + ". ");
        System.out.println("Current HP is " + hp + ".");
    }

}
```

【mainメソッドのクラス】

```Java
        Human h1 = new Human();
        h1.name = "Tanaka";
        h1.age = 25; 
        h1.address = "Tokyo";
        h1.hp = 100;
        h1.greet();

        Human h2 = new Human();
        h2.name = "Yamada"; 
        h2.age = 28; 
        h2.address = "Kanagawa";
        h2.hp = 130;
        h2.greet();
```
1番目のコードと実行結果は変わらないが、1番目のコードはインスタンス化後にそれぞれのオブジェクトに再代入する必要があったのに対し、このコンストラクタを使用する記述ではインスタンス化と同時に値を設定できる

以下引数ありのコンストラクタで、実際にインスタンス化時にそれぞれのオブジェクトに値を設定する

【Humanクラス】

```Java
public class Human {

    String name;
    int age;
    String address;
    int hp;

    //引数なしのコンストラクタ
    public Human() {
        name = "未設定";
        age = 0;
        address = "未設定";
    }

    //引数を3つ指定したコンストラクタ
    public Human(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void greet() {
        hp = hp - 10;
        System.out.print("My name is " + name + ".");
        System.out.print("I'm " + age + " years old.");
        System.out.print("I live in " + address + ". ");
        System.out.println("Current HP is " + hp + ".");
    }

}
```

【mainメソッドのクラス】

```Java
public static void main(String[] args) {
        Human h1 = new Human();
        h1.name = "Tanaka";
        h1.age = 25; 
        h1.address = "Tokyo";
        h1.hp = 100;
        h1.greet();

        Human h2 = new Human("Yamada", 28, "Kanagawa");
        h2.hp = 130;
        h2.greet();

    }
```

この時の実行結果も同じ
変数h1のインスタンスでは引数なしのコンストラクタを使用し、変数h2のインスタンスでは引数を3つ指定したインスタンスを使用している
引数んを指定したコンストラクタには明示的にthis、つまり「このクラスの」フィールドのname = 引数nameとしている
（thisをつければフィールド、つけなければ引数を指定する）

また1番初めのコンストラクタを使用しないパターンでも、実際にはインスタンス化時にデフォルトコンストラクタが自動的に呼び出されている（引数も中身もないため実行結果には何も出てこないが）

しかし引数ありのコンストラクタを使用する場合、デフォルトコンストラクタは追加されないため、上述のコードの場合自分で引数なしのコンストラクタを記述しなければ、引数を指定していない変数h1はコンパイルエラーとなる

またコンストラクタ内で別のコンストラクタを呼び出すことも可能
上述の引数なし、ありのコストラクタを別々で記述する場合、例えば引数を2つ指定するコンストラクタを新しく記述するとしても、引数なしのコンストラクタで行った代入処理と一部同じことをする必要がある
コンストラクタをつなぎ合わせることによりそれぞれのコンストラクタに同じような代入処理を記述する必要がなくなり、ソースコードもすっきりする

【Humanクラス】

```Java
public class Human {

    String name;
    int age;
    String address;
    int hp;

    public Human() {
        this("未設定");
    }

    public Human(String name) {
        this(name, 0);
    }

    public Human(String name, int age) {
        this(name, age, "未設定");
    }

    public Human(String name, int age, String address) {
        this.name = name;
        this.age = age;
        this.address = address;
    }

    public void greet() {
        hp = hp - 10;
        System.out.print("My name is " + name + ".");
        System.out.print("I'm " + age + " years old.");
        System.out.print("I live in " + address + ". ");
        System.out.println("Current HP is " + hp + ".");
    }
```

【mainクラスのメソッド】

```Java
public static void main(String[] args) {
        Human h1 = new Human();
        h1.name = "Tanaka";
        h1.age = 25;
        h1.address = "Tokyo";
        h1.hp = 100;
        h1.greet();

        Human h2 = new Human("Yamada", 28, "Kanagawa");
        h2.hp = 130;
        h2.greet();

        Human h3 = new Human("Suzuki");
        h3.hp = 200;
        h3.greet();
    }
```

コンストラクタを連鎖的につなげ、実際に代入する処理は1つのコンストラクタに限定し、それ以外のコンストラクタからは限定された部分を呼び出すようにすることでそれぞれのコンストラクタに同じような代入処理を書かなくてもよくなる