CodeGym では、最初のレッスンから文字通りJava thisキーワードを学生に紹介します。時間が経つにつれて、その意味が明らかになります。しかし、振り返ってみると、長い間、このキーワードの「禅」を理解できなかったと自認する人も多いだろう。この記事では、まだ理解できていない人のために、 thisキーワードの秘密を覆い隠します。Schildtの Java リファレンスを持っていると、171 ページでthisキーワードが次のとおりであることがわかります。メソッドがそれを呼び出したオブジェクトを参照するために必要です。それでレッスンを終了してもいいでしょう。しかし、詳細が必要です。原則として、これは 次の 2 つの場合に使用する必要があります。
- インスタンス変数とメソッド/コンストラクタ変数が同じ名前の場合。
- 特定のタイプのコンストラクター (デフォルト コンストラクターやパラメーター化されたコンストラクターなど) を別のタイプのコンストラクターから呼び出す必要がある場合。これは、明示的なコンストラクター呼び出しとも呼ばれます。
例 1: インスタンス変数とメソッド変数が同じ名前です。
name フィールドを定義するHumanクラスがあるとします。 name変数のセッターを作成しましょう(セッターは完全に機能します。ここにはキャッチはありません)。
class Human {
String name;
public void setName(String newName) {
name = newName;
}
}
String newName をsetNameセッター メソッドに 渡すことに注意してください。新しい変数を宣言しましたが、 setNameメソッドを囲む中括弧 ({}) 内でのみ表示されるため、任意の名前を付けることができます。セッターには次の 1 行があることに注意してください。
name = newName;
ここでは、 newName という新しい変数を導入し、それをオブジェクトの既存のname変数に割り当てました。多くのプログラマーは、最終的には同じことについて話しているのに、新しい名前の変数を導入するのは奇妙に感じるかもしれません。つまり、Humanクラスの name フィールドについて話しているのです。そのため、Java の作成者は、同じ変数名を便利に使用する方法を考え出しました。言い換えれば、同じものを表す変数になぜ 2 つの名前があるのかということです。言い換えれば、次のようなことをしたいのです。
class Human {
String name;
public void setName(String name) {
name = name;
}
}
しかし、ここで問題が発生します。同じ名前の変数が 2 つあります。1 つのString 名はHumanクラスに属し、もう 1 つのString 名はそのsetNameメソッドに属します。その結果、セッターに次の行を記述したときに、JVM はどの変数を参照しているのかを認識できません。
name = name;
Java は、最も近い名前変数、つまりsetNameメソッドの名前変数を意味していると想定します。 つまり、単にメソッドの名前変数をそれ自体に割り当てているだけであることがわかります。もちろんそれは意味がありません。したがって、この言語には、 Humanクラスのname変数とsetNameメソッドのname変数を区別する何らかの方法が必要でした。この問題は、 thisキーワードを導入することで解決されました。この場合、メソッド内の変数ではなく、 Humanクラスのインスタンスに関連付けられた変数を参照するつもりであることを示します。記事の冒頭で述べたように、呼び出し元のオブジェクトを指します。その結果、setNameメソッドは、作成されたオブジェクトに人の名前を設定します。以下は、 thisキーワードを使用しないプログラムのコードです。このコードはHumanオブジェクトを作成し、それに名前を割り当てます。 そして、 thisキーワードを含むコードは次のとおりです。
public class Solution {
public static void main(String[] args) {
Human human1 = new Human();
human1.setName("Vinny");
human1.print();
}
}
class Human {
String name;
public String getName() {
return name;
}
public void setName(String name){
this.name = name;
}
void print() {
System.out.println(name);
}
}
したがって、これにより、同じことを示す新しい変数の導入を回避でき、コードがすっきりし、余分な変数が少なくなります。
例 2: 明示的なコンストラクター呼び出しにこれを使用する
あるコンストラクターから別のコンストラクターを呼び出すことは、(奇妙なことに) 複数のコンストラクターがあり、別のコンストラクターで以前に記述された初期化コードを新しいコンストラクターで複製したくない場合に便利です。混乱している?見た目ほど怖くないです。以下のコードを見てください。Humanクラス用の 2 つのコンストラクターがあります。
class Human {
int age;
int weight;
int height;
Human(int age, int weight) {
this.age = age;
this.weight = weight;
}
Human(int age, int weight, int height) {
// Call the constructor with two parameters
this(age, weight);
// and then initialize the missing variable
this.height = height;
}
}
ここでは、最初に、 int ageとint Weight という 2 つのパラメーターを備えたコンストラクターを提供しました。コードが 2 行あるとします。
this.age = age;
this.weight = weight;
その後、3 つのパラメーターを持つ別のコンストラクターを追加し、既存の年齢パラメーターと体重パラメーターに身長を追加することにします。新しいコンストラクターは次のように記述できます。
this.age = age;
this.weight = weight;
this.height = height;
ただし、このコンストラクターで既存のコードを繰り返す代わりに、thisキーワードを使用して、2 つのパラメーターを指定してコンストラクターを明示的に呼び出すことができます。
this(age, weight);
// and then initialize the missing variable:
this.height = height;
これは、3 つのパラメーターのコンストラクターに次のように言っているかのようです。
- 2 つのパラメーターを持つこの別のコンストラクターを呼び出します
- 次に、別の変数を追加します。
GO TO FULL VERSION