初心者のJavaプログラミング

プログラミングガチ初心者がIT業界を目指して頑張ります。

【第16回】初心者のJavaプログラミング【this】

こんばんは。
2連投です。
今回はthisキーワードについてです。

thisとはなんぞや

thisには2通りの使い方があります。
とりあえず教科書通りの説明を書きます。
「thisは実行中のオブジェクトを指します。」
もう一つの使い方。
コンストラクタから同じクラスの別のコンストラクタを呼び出すために使う」
分かりそうでわからない。
まずは一つ目の説明から。

thisは実行中のオブジェクトを指す

具体的なコードを見ます。

class Car {
	// インスタンス変数
	String carType;
	String color;
	int    size;

	// コンストラクタ1
	Car(String carType, String color, int size) {
	  this.carType = carType;
	  this.color = color;
	  this.size = size;
	}
}

class CarTest {
	public static void main( String args[] ) {
		// car2オブジェクトをコンストラクタ1を使って生成
		Car car = new Car("セダン", "シルバー", 12);
		System.out.println(car.carType);
		System.out.println(car.color);
		System.out.println(car.size);
	}
}

コンストラクタ1のところでthisキーワードが出てきていますね。
説明するのが難しい...
まず、CarTestクラス内の
Car car = new Car("セダン", "シルバー", 12);
の説明から。前回もやりましたが、この一文は、
「Carクラス(型)の参照型変数であるcarオブジェクトを宣言します。carオブジェクトをCar("セダン", "シルバー", 12)で初期化して、newで実際にメモリ領域にcarオブジェクトを確保します。」
という意味です。
もっと細かく。
Car("セダン", "シルバー", 12)の意味は、
「CarクラスにあるCarコンストラクタさん。"セダン", "シルバー", 12という情報をあげますから、それを元に初期化してくれ!」
という意味になります。
そうするとその情報を受け取ったCarクラスのCar(String carType, String color, int size)コンストラクタさんが反応します。
与えられた情報の順番、型ともに間違い無し。よしおれの出番か、という風にコンストラクタさんのテンションが上がります。
そして与えられた情報を元にこんな処理をコンストラクタさんはしてますね。

this.carType = carType;
this.color = color;
this.size = size;

やっとthisの登場です。
thisは実行中のオブジェクトをさすのでしたね。
となるとこの場合は今carオブジェクトの初期化の処理で飛んできたので、このthisはcarオブジェクトのことを指します。
なのでこの場合の、
this.carType = carType;
という文の意味は
「carオブジェクトの状態(変数)に、与えられた情報"セダン"を代入します」
ということになります。
以下の2文も同じ意味になります。

どうでしょう。わかりましたでしょうか。
すみませんが、これが僕の説明力の限界ですw
一応絵ものせときますw
f:id:fightingneetkun:20140806205702p:plain
わかりづらいw

コンストラクタ内でのthis

Carクラス内が以下のような感じだったとします。

class Car {
	// インスタンス変数
	String carType;
	String color;
	int    size;

	// コンストラクタ1
	Car(String carType, String color, int size) {
	 	this.carType = carType;
	 	this.color = color;
	 	this.size = size;
	}
	// コンストラクタ2
	Car(String carType, String color) {
	 	this.carType = carType;
	 	this.color = color;
	 	this.size = 15;
	}
	// コンストラクタ3
	Car(String carType){
		this.carType = carType;
		this.color = "青";
		this.size = 10;
	}
}

この表記の仕方を簡単にするのが第2のthisの使い方です。
簡単にすると以下のようになります。

class Car {
	// インスタンス変数
	String carType;
	String color;
	int    size;

	// コンストラクタ1
	Car(String carType, String color, int size) {
	 	this.carType = carType;
	 	this.color = color;
	 	this.size = size;
	}
	// コンストラクタ2
	Car(String carType, String color) {
	 	this(carType, color, 12);
	}
	// コンストラクタ3
	Car(String carType){
		this(carType, "青", 10);
	}
}

なんとも簡潔になりましたね。
動きを説明していきます。

じゃあまず、コンストラクタ2を呼ばれた時のことを考えてみましょう。
コンストラクタ2は引数を2つ受け取るバージョンのコンストラクタですね。
情報を受け取ったら、
this(carType, color, 12)
という処理が走りますね。
このthisは何を指すかというと、引数を3つもち、かつ1つ目の引数がString型、2つ目の引数がString型、3つ目の引数がint型、であるCarクラス内のコンストラクタのことを指します。
そんな都合のいいコンストラクタなんてあるのかよ...
アルンデス!

まあ勝手にあるというか、ちゃんと定義したんですけどねw
そうですコンストラクタ1のことです。
こいつの処理に飛ぶんですね。
だから受け取った情報をコンストラクタ2が処理しないで、コンストラクタ1にまわして処理させるんですね。
なんとなく分かっていただけたら幸いですw

ではそもそもなんでこんなことをするのでしょうか。
確かに最初の方法は冗長ですが、分かりやすいし、わざわざコンストラクタ同士情報で情報を渡し合わない方が処理が早くなりそうだし、そもそも2度手間なのではと思いませんか。
私はそう思ったのでテンテーに質問しました。

回答はこんな感じです。
コンストラクタ1が色々テスト済みで完璧に動くと仮定します。
そうなったときに、また別のコンストラクタを定義していくという作業は、バグが発生しやすく、あまり良い方法ではないので、完璧に動作するコンストラクタ1の方に処理を投げるのが合理的なのだそうです。


thisの説明はこんな感じです。

よし、とりあえず今日はこの辺で終わります。
2つ記事を書くのは結構しんどかったですw

参考書

独習Java 第4版

独習Java 第4版