Developer

【はじめてのJava】コンストラクタのオーバーロード【オブジェクトとクラス編】
2021.07.20
Lv1

【はじめてのJava】コンストラクタのオーバーロード【オブジェクトとクラス編】

はじめてのJava

このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。


オブジェクトとクラス編

オブジェクトとクラス編では、Javaを扱う上で非常によく出てくる「オブジェクト」や「クラス」について扱っていきます。

前回は「引数付きのコンストラクタ」について扱いました。

今回は「コンストラクタのオーバーロード」について扱います。


目次


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

オーバーロードとは同一のクラスの中に同名メソッドを複数定義することでした。

コンストラクタもメソッド同様、オーバーロードして複数定義することができます。

詳しく見ていきましょう。


コンストラクタをオーバーロードする

以前説明した通り、メソッドは「引数の違いから区別可能」であれば、同名のメソッドを定義することができます。これをメソッドのオーバーロードと言いました。

コンストラクタも同様に、「引数の違いから区別が可能」であれば複数定義することができます。

これを コンストラクタのオーバーロード と言います。

Carクラスを例に、具体例を見ていきましょう。

 

コンストラクタのオーバーロードの書き方

前回作成したCarクラスを基に、コンストラクタのオーバーロードの書き方を見ていきます。

前回作成したCarクラスは以下の通りでした。

class Car{
  double speed;
  String color;
 
  Car(String color){
    this.color = color;
  }
 
  void accell(){
    speed += 10;
  }
 
  //↓オーバーロードしたaccellメソッド
  void accell(int s){
    if(s < 0){
      //sが負の数だった場合、メソッドの処理を終了する
      return;
    }
    speed +=s;
  }
 
}

説明の都合上、車のナンバーを表すインスタンス変数としてString型のnumberPlateを追加します。

追加後のCarクラスは以下の通りです。

class Car{
  double speed;
  String color;
  String numberPlate; //ここを追加1
 
  Car(String color){
    this.color = color;
  }
 
  void accell(){
    speed += 10;
  }
 
  //↓オーバーロードしたaccellメソッド
  void accell(int s){
    if(s < 0){
      //sが負の数だった場合、メソッドの処理を終了する
      return;
    }
    speed +=s;
  }
 
}

今のままではインスタンス化した際のnumberPlateの初期値はnullになってしまいます。

しかし、(あくまでイメージですが)車には必ずナンバーが設定されています。

そこで、まずは既存のコンストラクタを改造してnumberPlateの初期値が”z00-00″に設定されるようにしましょう。

改造を反映すると以下のようになります。

class Car{
  double speed;
  String color;
  String numberPlate; //ここを追加1
 
  Car(String color){
    this.color = color;
    this.numberPlate = "z00-00"; //ここを追加2
  }
 
  void accell(){
    speed += 10;
  }
 
  //↓オーバーロードしたaccellメソッド
  void accell(int s){
    if(s < 0){
      //sが負の数だった場合、メソッドの処理を終了する
      return;
    }
    speed +=s;
  }
 
}

これで、Carクラスをインスタンス化した際に、colorの初期値が任意の値に、numberPlateの初期値が”z00-00″に設定されるようになりました。

 

一見するとこれでnumberPlateの値はnullではなくなったのでOKのように見えます。

しかし、このままではすべての車のnumberPlateの初期値が”z00-00″で統一されてしまいます。

そこで、colorのみ指定された場合はnumberPlateは”z00-00″に、colorとnumberPlateの両方が指定された場合は両方とも指定の値で初期化されるようにします。

Carクラスのコンストラクタをオーバーロードし、以下のようにします。

class Car{
  double speed;
  String color;
  String numberPlate; //ここを追加1
 
  Car(String color){
    this.color = color;
    this.numberPlate = "z00-00"; //ここを追加2
  }

  //ここから追加3
  Car(String color, String numberPlate){
    this.color = color;
    this.numberPlate = numberPlate;
  }
  //ここまで追加3

  void accell(){
    speed += 10;
  }
 
  //↓オーバーロードしたaccellメソッド
  void accell(int s){
    if(s < 0){
      //sが負の数だった場合、メソッドの処理を終了する
      return;
    }
    speed +=s;
  }
 
}

これでコンストラクタをオーバーロードして、colorのみ設定する場合と、colorとnumberPlateを設定する場合の2つのコンストラクタが作成できました。

これでコンストラクタのオーバーロードができました。

 


動作確認

では、実際に動作確認してみましょう。

MyCarDriveクラスを利用して動作を確認します。

今回のMyCarDriveクラスは以下の通りです。

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

    //Car myCar = new Car(); //今回は使わない
    Car myCar = new Car("blue"); //前回と同じ
    Car myCar2 = new Car("green", "x12-34");

    //↑でインスタンス化したのみで、他に何も操作を行わない
    System.out.println("myCar -> " + myCar.color + ":"+ myCar.numberPlate); //myCarのcolorとnumberPlateを確認
    System.out.println("myCar2 -> " + myCar2.color + ":" + myCar2.numberPlate); //myCar2のcolorとnumberPlateを確認

  }
}

今回も、インスタンス化以外は特にインスタンス変数の値を変更する操作はしていません。

実行結果は以下の通りです。

myCarのcolorはblueになっており、インスタンス化の時に指定していないnumberPlateはz00-00になっていることが確認できます。

myCar2のcolorはgreenに、numberPlateはインスタンス化の時に指定したx12-34になっていることが確認できます。

これで、コンストラクタのオーバーロードができました。

 


コラム:コンストラクタのオーバーロードの注意点

これでコンストラクタのオーバーロードができました。

今、Carクラスには以下の2つのコンストラクタがあります。

  • colorだけを指定するコンストラクタ(numberPlateは固定値)
  • colorとnumberPlateの両方を指定するコンストラクタ

せっかくですので、追加で「speedだけを指定するコンストラクタ(colorとnumberPlateは固定値)」を追加する場合を考えてみましょう。

追加するコンストラクタは以下の通りです。

Car(double speed){
  this.speed = speed; //speedを設定
  this.color = "white"; //colorはwhiteで固定
  this.numberPlate = "z00-00"; //numberPlateも固定
}

このコンストラクタは先ほどのCarクラスに追加しても問題ありません。

では、さらに追加で「numberPlateだけを指定するコンストラクタ(colorは固定値)」を追加する場合を考えてみましょう。

追加するコンストラクタは以下の通りです。

Car(String numberPlate){
  this.color = "white"; //colorはwhiteで固定
  this.numberPlate = numberPlate;
}

このコンストラクタには文法的には間違いがありません。しかし、これを先ほどのCarクラスに組み込むとコンパイルエラーとなります。

なぜならば引数のデータ型の順番がcolorを設定するコンストラクタと完全に一致しているためどちらのコンストラクタを呼び出しているのか区別することができないためです。

この辺りの仕組みもメソッドのオーバーロードの時と同じです。

Carクラスに2つのコンストラクタを追加した例

class Car{
  double speed;
  String color;
  String numberPlate; //ここを追加1
  
  //こちらは追加可能
  Car(double speed){
    this.speed = speed; //speedを設定
    this.color = "white"; //colorはwhiteで固定
    this.numberPlate = "z00-00"; //numberPlateも固定
  }

  Car(String color){
    this.color = color;
    this.numberPlate = "z00-00";
  }

  // こちらは↑のコンストラクタと呼び分けができないためコンパイルエラーになる。
  //Car(String numberPlate){
  //  this.color = "white"; //colorはwhiteで固定
  //  this.numberPlate = numberPlate;
  //}

  /* 省略 */
  
}

クラスを設計する際は、どのインスタンス変数の値を指定できるようにするのかよく考えたうえで設計する必要があります。

 


ソースコード

今回使用したソースコードをまとめて記載します。2つのソースコードは同じディレクトリに配置する必要があります。

Car.java

class Car{
  double speed;
  String color;
  String numberPlate; //ここを追加1
  
  Car(String color){
    this.color = color;
    this.numberPlate = "z00-00"; //ここを追加2
  }
 
  //ここから追加3
  Car(String color, String numberPlate){
    this.color = color;
    this.numberPlate = numberPlate;
  }
  //ここまで追加3
 
  void accell(){
    speed += 10;
  }
  
  //↓オーバーロードしたaccellメソッド
  void accell(int s){
    if(s < 0){
      //sが負の数だった場合、メソッドの処理を終了する
      return;
    }
    speed +=s;
  }
  
}

MyCarDrive.java

public class MyCarDrive{
  public static void main(String[] args){
 
    //Car myCar = new Car(); //今回は使わない
    Car myCar = new Car("blue"); //前回と同じ
    Car myCar2 = new Car("green", "x12-34");
 
    //↑でインスタンス化したのみで、他に何も操作を行わない
    System.out.println("myCar -> " + myCar.color + ":"+ myCar.numberPlate); //myCarのcolorとnumberPlateを確認
    System.out.println("myCar2 -> " + myCar2.color + ":" + myCar2.numberPlate); //myCar2のcolorとnumberPlateを確認
 
  }
}

まとめ

コンストラクタもオーバーロードすることができる
引数のデータ型の違いからどのコンストラクタで初期化が実行されるか区別される

次回

次回はコンストラクタの注意点について扱います。


はじめてのJavaシリーズの目次はこちら
オブジェクトとクラス編はこちら


java 11 の練習問題一覧はこちら
はじめてのJavaシリーズの練習問題一覧はこちら