初めまして。まると申します。
初めてのブログ更新ですね。
これから研修で学んだことの中から、「なるほど」と思ったことや自分の中でもう少し整理したい内容などを取り上げてアウトプットしていきたいと思います。
人生で初めて書くブログなので、何卒お手柔らかに・・・。
記念すべき第一回目は、コンストラクタについて。
初めてこの言葉を聞いた時の私は、とりあえず検索をかけました。
コンストラクタとは…
コンストラクタとは、オブジェクト指向プログラミング言語において、クラスをインスタンス化する際に実行される特別なメソッド。インスタンスの初期化処理などを記述する。
引用元:IT用語辞典 e-Words
な、なるほど・・・?
実際にコードで見てみます。
まずはコンストラクタを利用していない例です。
//勇者の情報を定義
class Hero {
String name; //勇者の名前
int hp; //勇者の体力
}
//勇者を呼び出すメインクラス
class Main {
public static void main(String[] args) {
//インスタンスを生成
Hero hero1 = new Hero();
//顧客の名前と体力を表示
System.out.println("名前:" + hero1.name);
System.out.println("体力:" + hero1.hp);
}
}
【実行結果】
名前:null
体力:0
名前も体力もない勇者が爆誕してしまいました…。
それもそのはず、勇者クラスには名前と体力を設定する変数だけが用意されており、メインクラスのメインメソッドでも勇者のインスタンスを生成しただけで(11行目)、変数には何も値を設定していませんでした。
このように、newでクラスをインスタンス化した際に変数に対して何の値も設定しない場合、それぞれの変数にはあらかじめ決められた初期値が設定されます。
また、初期値はその変数のデータ型で決定します。(下図参照)
型 | 初期値 |
数値型 (int、short、long) | 0 |
文字型 (char) | ‘\u0000’ |
boolean型 | false |
参照型 (String、配列、クラス) | null |
よって、String型の勇者の名前には「null」、int型の勇者の体力には「0」が設定されていました。
初期値以外の値を設定するには、そのための処理の記述が必要という訳です。
//勇者の情報を定義
class Hero {
String name; //勇者の名前
int hp; //勇者の体力
}
//勇者を呼び出すメインクラス
class Main {
public static void main(String[] args) {
//インスタンスを生成
Hero hero1 = new Hero();
//勇者の名前と体力を設定
hero1.name = "アーサー";
hero1.hp = 150;
//勇者の名前と体力を表示
System.out.println("名前:" + hero1.name);
System.out.println("体力:" + hero1.hp);
}
}
【実行結果】
名前:アーサー
体力:150
14・15行目の値設定処理を追加することで、やっと勇者に名前と体力を与えることができました!
今回は設定値が名前と体力のみ、勇者も一人だけだったので問題はなさそうです。
ですが、さらに設定値が増え、勇者も複数人出現させる必要があったら、いちいちインスタンス化の度に値設定処理を書き加えるのは大変そうです…。
そこで使うのがコンストラクタです。
上記のコードをコンストラクタを用いて記載すると以下のようになります。
//勇者の情報を定義
class Hero {
String name; //勇者の名前
int hp; //勇者の体力
//コンストラクタ
Hero(String name,int hp) {
//引数で受け取った値を、勇者の名前と体力にそれぞれ設定
this.name = name;
this.hp = hp;
}
}
//勇者を呼び出すメインクラス
class Main {
public static void main(String[] args) {
//インスタンスを生成
Hero hero1 = new Hero("アーサー", 150);
//勇者の名前と体力を表示
System.out.println("名前:" + hero1.name);
System.out.println("体力:" + hero1.hp);
}
}
【実行結果】
名前:アーサー
体力:150
7~11行目がコンストラクタの箇所です。
コンストラクタはインスタンスを生成した際に呼ばれる特別なメソッドで、今回の場合は18行目の「new Hero(“アーサー”, 150)」で呼び出されています。
この()の中身の引数を、コンストラクタ内の処理で勇者クラス側の変数にそれぞれ設定しているイメージです。
記述したメソッドがコンストラクタであるとみなされる条件は、以下の二つです。
①メソッド名とクラスが同一であること
②戻り値が記載されていないこと
コンストラクタは、他のメソッドと同様にオーバーロードすることが可能です。
試しに、以下の設定の勇者を作成するソースを書いてみました。
勇者1:名前が「アーサー」、体力「150」
勇者2:名前が「未定」、体力「80」
//勇者の情報を定義
class Hero {
String name; //勇者の名前
int hp; //勇者の体力
//コンストラクタ1
Hero(String name,int hp) {
//引数で受け取った値を、勇者の名前と体力にそれぞれ設定
this.name = name;
this.hp = hp;
}
//コンストラクタ2
Hero(int hp) {
//名前は「未定」とする
//引数で受け取った値を、勇者の体力に設定
this.name = "未定";
this.hp = hp;
}
}
//勇者を呼び出すメインクラス
class Main {
public static void main(String[] args) {
//インスタンスを生成
Hero hero1 = new Hero("アーサー", 150);
Hero hero2 = new Hero(80);
//勇者1の名前と体力を表示
System.out.println("名前:" + hero1.name);
System.out.println("体力:" + hero1.hp);
//勇者2の名前と体力を表示
System.out.println("名前:" + hero2.name);
System.out.println("体力:" + hero2.hp);
}
}
【実行結果】
名前:アーサー
体力:150
名前:未定
体力:80
26行目のインスタンス化では引数をString型・int型の二つで呼び出しているのでコンストラクタ1を、
27行目では引数がint型の一つのみなのでコンストラクタ2を呼び出しています。
コンストラクタ2では、名前を受け取っていないので「未定」という固定文言を設定しています。
実行結果も問題なさそうです。
ですが、このソースコード、実はもっと綺麗に書くことができます。
【修正前】
//コンストラクタ1
Hero(String name,int hp) {
//引数で受け取った値を、勇者の名前と体力にそれぞれ設定
this.name = name;
this.hp = hp;
}
//コンストラクタ2
Hero(int hp) {
//名前は「未定」とする
//引数で受け取った値を、勇者の体力に設定
this.name = "未定";
this.hp = hp;
}
【修正後】
//コンストラクタ1
Hero(String name,int hp) {
//引数で受け取った値を、勇者の名前と体力にそれぞれ設定
this.name = name;
this.hp = hp;
}
//コンストラクタ2
Hero(int hp) {
//コンストラクタ1を呼び出し
this("未定", hp);
}
ちょっとすっきりしました。
11行目ではthis()を利用してコンストラクタ1を呼び出しています。
同じクラスのメソッドを呼び出すという認識だと、
this.Hero(“未定”, hp);
で呼び出せそうな気がしますが、コンストラクタの場合この記述方法はNGです。
今回は変数を二つしか用意しなかったのであまり恩恵を感じられないかもしれませんが、
大量の変数があってそれぞれの値設定のパターンを用意しなくてはいけない場合に、this()を使いこなせると良さそうです。
学習して知識として知っているつもりでも、実際にソースを書くとすんなりと書けないことも多いので、実践を重ねて経験値を積んでいけたらと思います。
今回はここまでです。
有難うございました!