【17章】Javaを学ぼう

前回の記事は「【15章】Javaを学ぼう」で作成した自己紹介プログラムを改善していきましたが、今回はコンストラクタのオーバーロードを中心に学び、作成した自己紹介プログラムをさらに改善していきたいと思います。
私自身のアウトプットの場となりますので、よろしくお願いいたします！

##前章で作成した自己紹介プログラム（前提）
```java:Person.java
class Person {
 public static int count = 0;
 public String firstName;
 public String lastName;
 public int age;
 public double height, weight;
 
 Person(String firstName, String lastName, int age, double height, double weight) { 
  this.count ++; 
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.height = height;
  this.weight = weight;
 }

 public String fullName() {
  return this.firstName + " " + this.lastName;
 }
 
 public double bmi() {
  return this.weight / this.height / this.height;
 }

 public static void printCount() {
  System.out.println("合計" + Person.count + "人です");
 }

 public void printData() {
  System.out.println("私の名前は" + this.fullName() + "です");
  System.out.println("年齢は" + this.age + "歳です");
  System.out.println("BMIは" + Math.round(this.bmi()) + "です");
 }
}
```

```java:Main.java
class Main {
 public static void main(String[] args) {
  Person person1 = new Person("John", "Connor", 28, 1.7, 65.0);
  person1.printData();
  Person person2 = new Person("Mia", "Olivia", 20, 1.5, 45.0);
  person2.printData();

  Person.printCount();
 }
}
```

出力結果↓

```java:コンソール
私の名前はJohn Connorです
年齢は28歳です
BMIは23です
私の名前はMia Oliviaです
年齢は20歳です
BMIは20です
合計は2人です
```

#コンストラクタのオーバーロード
オーバーロードとは、引数の型や数が違えば同名のメソッドを定義できる仕組みです。
##ミドルネームを追加
インスタンスがmiddleNameというフィールドも持つようにします。しかし、コンストラクタの引数に不用意にmiddleNameを追加してしまうと、middleNameを持たない人はインスタンスを生成するときにエラーが発生してしまいます。この問題を解決するために、コンストラクタを**オーバーロード**することができます。つまり、middleNameを引数に受け取らないものと、受け取るもの、2つのコンストラクタを定義すれば、解決できます。

```java:Person.java
class Person {
 public static int count = 0;
 public String firstName;
 public String middleName;  //インスタンスフィールドmiddleNameを定義
 public String lastName;
 public int age;
 public double height, weight;
 
 Person(String firstName, String lastName, int age, double height, double weight) { 
  this.count ++; 
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.height = height;
  this.weight = weight;
 }

 // middleNameを受け取るコンストラクタを定義
 Person(String firstName, String middleName, String lastName, int age, double height, double weight) { 
  this.firstName = firstName;
  this.middleName = middleName;
  this.lastName = lastName;
  this.age = age;
  this.height = height;
  this.weight = weight;
 }

 public String fullName() {
   if(this.middleName == null) {
     return this.firstName + " " + this.lastName;
   } else {
     return this.firstName + " " + this.middleName + " " + this.lastName;
   }
 }
 
 public double bmi() {
  return this.weight / this.height / this.height;
 }

 public static void printCount() {
  System.out.println("合計" + Person.count + "人です");
 }

 public void printData() {
  System.out.println("私の名前は" + this.fullName() + "です");
  System.out.println("年齢は" + this.age + "歳です");
  System.out.println("BMIは" + Math.round(this.bmi()) + "です");
 }
}
```

また、middleNameを追加したことによって、条件分岐を行い、middleNameの値がセットされているインスタンスは、middleNameを含めたフルネームを、そうでないインスタンスならmiddleNameを含めないフルネームを返せるようにしています。

```java:Main.java
class Main {
 public static void main(String[] args) {
  Person person1 = new Person("John", "Connor", 28, 1.7, 65.0);
  person1.printData();
  Person person2 = new Person("Mia", "Christopher", "Olivia", 20, 1.5, 45.0);
  person2.printData();

  Person.printCount();
 }
}
```

これでmiddleNameを追加することができました。しかし、コンストラクタをオーバーロードしたのはいいですが、2つのコンストラクタの中身はほとんど重複しています。コードの重複は、修正などを大変にしてしまうため好ましくありません。
**this()**とすると、コンストラクタから他のコンストラクタを呼び出すことができます。this()はコンストラクタを呼び出すための特別なメソッドで、()に引数を渡すことも可能です。
また、thisはコンストラクタの**先頭でしか呼び出せません**ので注意が必要です。
それでは修正していきます。

```java:Person.java
class Person {
 public static int count = 0;
 public String firstName;
 public String middleName;  
 public String lastName;
 public int age;
 public double height, weight;
 
 Person(String firstName, String lastName, int age, double height, double weight) { 
  this.count ++; 
  this.firstName = firstName;
  this.lastName = lastName;
  this.age = age;
  this.height = height;
  this.weight = weight;
 }

 Person(String firstName, String middleName, String lastName, int age, double height, double weight) {
  this(firstName, lastName, age, height, weight);  // this()を用いて、コンストラクタを呼び出す
  this.middleName = middleName;
 }

 public String fullName() {
   if(this.middleName == null) {
     return this.firstName + " " + this.lastName;
   } else {
     return this.firstName + " " + this.middleName + " " + this.lastName;
   }
 }
 
 public double bmi() {
  return this.weight / height / height;
 }

 public static void printCount() {
  System.out.println("合計" + Person.count + "人です");
 }

 public void printData() {
  System.out.println("私の名前は" + this.fullName() + "です");
  System.out.println("年齢は" + this.age + "歳です");
  System.out.println("BMIは" + Math.round(this.bmi()) + "です");
 }
}
```

this()としたことで、すっきりとしたコードになりました。


今回はここまでにしたいと思います。次章ではカプセル化によってフィールドとメソッドへのアクセスを制限することを学んでいきたいと思います。今回まで改善をしてきた自己紹介プログラムは次章でも使用します。
よろしくお願いいたします！
最後までご覧いただきまして、ありがとうございました！