【はじめてのJava】コンストラクタの注意点【オブジェクトとクラス編】
はじめてのJava
このシリーズでは、初めてJavaやプログラミングを勉強する方向けに、Javaによるプログラミングの基礎を説明していきます。
目標レベルは、Javaの資格試験の一つである「Oracle Certified Java Programmer, Silver」(通称Java Silver)に合格できる程度の知識の習得です。
はじめてJavaやプログラムに触れる方にもできるだけわかりやすい解説を心がけていきます。
オブジェクトとクラス編
オブジェクトとクラス編では、Javaを扱う上で非常によく出てくる「オブジェクト」や「クラス」について扱っていきます。
前回は「コンストラクタのオーバーロード」について扱いました。
今回は「コンストラクタの注意点」について扱います。
目次
コンストラクタの注意点
コンストラクタはオブジェクトをインスタンス化する際に動きます。このコンストラクタについて、いくつか注意点があります。
具体的に見ていきましょう。
コンストラクタを書かない場合
まずは、コンストラクタを書かない場合を考えてみましょう。
例えば以前、メソッドの説明をした時のCarクラスは以下の通りでした。
Carクラス(メソッドの説明の時)
class Car{ double speed; String color; void accell(){ speed += 10; } }
このCarクラスにはコンストラクタがありません。しかし、インスタンス化することはできていました。
MyCarMainクラス(抜粋)
public class MyCarDrive{ public static void main(String[] args){ Car myCar = new Car(); //コンストラクタが無くてもインスタンス化できている!! /* 省略 */ } }
これはなぜでしょうか。見ていきましょう。
コンストラクタの自動追加
実は、クラスにコンストラクタを書かなかった場合は、引数がなく処理内容が空のコンストラクタが自動的に追加されます。
そのため、先ほどのCarクラスは実は以下のようになっています。
Carクラス(メソッドの説明時)
class Car{ double speed; String color; public Car(){ } //ここが自動的に追加されている void accell(){ speed += 10; } }
そのため、MyCarDriveクラスで問題なくインスタンス化できたのです。
コンストラクタがない場合の仕組みは以上の通りです。
ここだけ読むと「引数がないコンストラクタは自動追加されるんだ!」と考えたくなりますが、そこに罠があります。
罠の正体はこの記事を最後まで読むと明らかになります。
コンストラクタを書いた場合
先ほど、クラスにコンストラクタを書かなかった場合、コンストラクタが自動追加されると書きました。
では、クラスにコンストラクタを書いた場合はどうなるのでしょうか。
引数のないコンストラクタを書いた場合
引数のないコンストラクタを書いた場合は、コンストラクタの自動追加はされません。
もし、引数のないコンストラクタが自動追加されてしまった場合、2つのコンストラクタが競合してしまうためです。
引数のあるコンストラクタを書いた場合
では、引数のあるコンストラクタを書いた場合はどうなるでしょうか。
例えば、引数付きのコンストラクタで説明した時のCarクラスは以下の通りでした。
(説明に無関係なaccellメソッドは省略してあります。)
Carクラス(引数付きコンストラクタのみ記載)
class Car{ double speed; String color; //↓引数付きのコンストラクタ Car(String color){ this.color = color; } }
この時のMyCarMainクラスは以下の通りでした。
MyCarMainクラス
public class MyCarDrive{ public static void main(String[] args){ //Car myCar = new Car(); //ここはコメントなので実行されない Car myCar = new Car("blue"); //ここでインスタンス化されている System.out.println(myCar.color); //myCarのcolorを確認 } }
この時、myCarのcolorはインスタンス化の際に指定したblueになります。
引数なしでインスタンス化する
ではこの時、コメントアウトで消してあるほう(引数がないほう)のコンストラクタを呼び出してインスタンス化を行ったらどうなるでしょうか。
MyCarMainクラスを以下のように書き換えて試してみましょう。
MyCarMainクラス
public class MyCarDrive{ public static void main(String[] args){ Car myCar = new Car(); //こっちでインスタンス化 //Car myCar = new Car("blue"); //こっちをコメントアウト System.out.println(myCar.color); //myCarのcolorを確認 } }
この時は、myCarのcolorはnullになる…と思いきや、なんと、コンパイルエラーになります。
これはなぜでしょうか。
罠の正体
実は、先ほども書いた通り、 クラスにコンストラクタを書かなかった場合 は、引数がなく処理内容が空のコンストラクタが自動的に追加されます。
言い直すと クラスにコンストラクタが1つでも書かれていた場合は、コンストラクタは自動追加されません 。
これが罠の正体です。
今の状況を図にすると以下の通りです。
引数がないコンストラクタが必要なければこの状態で問題ありません。
しかし、ある理由から、一般的には引数がないコンストラクタを書くことが強く推奨されています。
(詳しくはクラスの継承の辺りで扱います。)
引数がないコンストラクタを書いておく
先ほど書いた通り、引数がないコンストラクタを書くことが強く推奨されています。
ですので、引数のないコンストラクタを追加しておきましょう。
Carクラス
class Car{ double speed; String color; //引数のないコンストラクタ Car(){ this.color = "red"; //colorの初期値がredになるように設定 } //↓引数付きのコンストラクタ Car(String color){ this.color = color; } }
MyCarDriveクラスは以下の通りです。
public class MyCarDrive{ public static void main(String[] args){ Car myCar1 = new Car(); Car myCar2 = new Car("blue"); System.out.println(myCar1.color); //myCar1のcolorを確認 System.out.println(myCar2.color); //myCar2のcolorを確認 } }
これで引数がないときはcolorの初期値がredに、引数があるときは引数の通りにcolorが設定されるようになりました。
ソースコード
今回使用したソースコードをまとめて記載します。2つのソースコードは同じディレクトリに配置する必要があります。
Carクラス
class Car{ double speed; String color; //引数のないコンストラクタ Car(){ this.color = "red"; //colorの初期値がredになるように設定 } //↓引数付きのコンストラクタ Car(String color){ this.color = color; } }
public class MyCarDrive{ public static void main(String[] args){ Car myCar1 = new Car(); Car myCar2 = new Car("blue"); System.out.println(myCar1.color); //myCar1のcolorを確認 System.out.println(myCar2.color); //myCar2のcolorを確認 } }
まとめ
クラスにコンストラクタを書かなかった場合は、引数なし、処理内容が空のコンストラクタが自動的に追加される。
クラスにコンストラクタを1つでも書いた場合はコンストラクタの自動追加は起こらない。
一般的に引数のないコンストラクタを作っておいたほうが良い。
次回
次回も引き続きクラスやオブジェクトに関する内容を扱います。
はじめてのJavaシリーズの目次はこちら
オブジェクトとクラス編はこちら