this キーワードRevised: Sep./11th/2002: Since: Dec./26th/2001
this とは何か通常のメンバー変数やメソッドは、どのオブジェクトのものかを識別するために、オブジェクト名を付して呼び出します。しかし、同じクラス内のフィールドやメソッドは、オブジェクト名を付けないで裸で参照できます。オブジェクト名を省略して呼び出すと、自クラス内のメンバーだと解釈されるのです。
field; // オブジェクト自身のメンバー変数呼び出し method(); // オブジェクト自身のメソッド呼び出し
しかし、メソッド内部で定義したローカル変数名と、当該メソッド自身が含まれるクラスのインスタンス変数名がバッティングしたときにはどうでしょうか?
class ThisTest {
String name = "Sugai"; // Member Variable
void meth() {
String name = "Tochihara"; // Local Variable
System.out.println(name); // 何が出力されますか?
}
}
結果としては、ローカル変数が優先されます。ここで出力されるのは "Tochihara" です。
このクラスを利用するコントロールクラスを作って、実行させてみましょう。上記のソースを ThisTest.java などの java ファイルに保存して、同じディレクトリに次のコントロールクラスも作ってコンパイルします。
ThisDemo.java:
class ThisDemo {
public static void main(String[] args) {
ThisTest obj = new ThisTest();
obj.meth();
}
}
C:\java>javac ThisDemo.java C:\java>java ThisDemo Tochihara C:\java>
メンバー変数名とローカル変数名が競合するときに、メンバー変数を参照するためには this キーワードを使います。
class ThisTest {
String name = "Sugai"; // Member Variable
void meth() {
String name = "Tochihara"; // Local Variable
System.out.println(this.name); // Member Variable
}
}
this.name は、「このオブジェクトのメンバー変数 name」 と言う意味です。自クラス内の変数やメソッドを裸で指定していたのは、実は this を省略していたのです。
前掲のコントロールクラスから、このサンプルを実行すると、次のようになります:
C:\java>javac ThisDemo.java C:\java>java ThisDemo Sugai C:\java>
this キーワードthisあるオブジェクトのフィールドやメソッドを参照するときには、そのオブジェクトを参照する変数を接頭辞に付けて、「どのオブジェクトの」インスタンス変数なのか、「どのオブジェクトの」メソッドなのかを識別していました。
obj.name; // obj オブジェクトの name 変数 obj.meth(); // obj オブジェクトの meth() メソッド
自分のクラスのメンバーであるメソッドや変数を指定する為には this が使えます。当該オブジェクト自身への参照が格納されています。オブジェクトを参照する変数の特殊なものと考えて良いでしょう。
thisメソッドに対しても、「実行中のこのオブジェクトの」ということを強調する為に this キーワードを使います。
this.method();
さて、変数 x があちこちに現れています。実行結果はどうなりますか?50ですか?100ですか?
ScopeDemo.java:
class Scope {
//メンバ変数
int x = 100;
//メソッド定義
void method(int x) {
System.out.println("method():" + x);
}
}
class ScopeDemo {
public static void main(String args[]) {
//インスタンス化
Scope obj = new Scope();
//メソッド呼び出し
obj.method(50);
System.out.println("main(): " + obj.x);
}
}
C:\java>javac ScopeDemo.java C:\java>java ScopeDemo method():50 main(): 100
メンバー変数とローカル変数は、JavaVM によって全く別のものとして管理されます。したがって、同じ名前を使っても上書きされたりはしません。
Scope クラスのメソッド method() 内部では単に x を呼び出してます。このスコープ内で有効な x は、メソッド引数で宣言されているローカル変数の x と、メンバー変数の x があります。バッティングしたら、this キーワードが付いていないのでローカル変数呼び出しとなります。ここでは、メソッド引数の x になるので、main() メソッドからメソッド引数代入された 50 がその値になります。
main() メソッドで obj オブジェクトの変数として参照されている x は、オブジェクトの変数=インスタンス変数=メンバー変数なので、 100 がその値になります。
このサンプルを次のように修正してみましょう:
class Scope {
//メンバ変数
int x=100;
//メソッド定義
void method(int x) {
System.out.println("method():" + this.x);
}
}
this キーワードは、「実行中のオブジェクト(自分自身への参照)」です。従って、 this.x ならば、「自分のメンバー変数 x」と宣言していることになります。
従って、実行結果は次のようになります:
C:\Java>javac ScopeDemo.java C:\Java>java ScopeDemo method():100 main(): 100
method() でも main() でも実行中のオブジェクト obj のインスタンス変数 x を参照しているので、同じ値 100 になりました。
ゲッター/セッターで this キーワードを使ってみましょう。
ThisDemo2.java
class This {
//フィールド
private int x;
//セッター・メソッド
public void setX(int x) {
this.x = x;
}
//ゲッター・メソッド
public int getX() {
return x;
}
//普通のメソッド
public void msg() {
System.out.println("This: " + x);
}
}
class ThisDemo2 {
public static void main(String[] args) {
//インスタンス化
This obj = new This();
//セッター呼び出し
obj.setX(10);
//ゲッター呼び出し
int x = obj.getX();
//メソッド呼び出し
obj.msg();
// 標準出力
System.out.println("main: " + x);
}
}
セッターでは、メソッド引数で初期化されているローカル変数と、フィールドの両方を同時に使っています。修飾子無しで指定するとローカル変数が参照されますので、フィールドを参照する為に this キーワードを使っています。
C:\Java>javac ThisDemo2.java C:\Java>java ThisDemo2 This: 10 main: 10