thisって何ですか?
という質問については、申し訳ありませんが他のページを参照して下さい。
ここでは、Javaで this を使うことによるメリット・デメリットについて考えてみます。
例えば、以下のようなクラスを考えます。
class ClassA {
private int value = 10;
public void func() {
System.out.println(value);
System.out.println(this.value);
}
}
このロジックは正常な文であり、実行すると画面には
10 10
と同じ結果が表示されます。
ではここで、後者にはなぜ this を付けているのでしょうか?
一般的に言われているのは「その方がフィールドだと明確にわかるから」のような事でしょうか。
例えば…
class ClassA {
private int value = 10;
public void func() {
private int localValue = 20;
System.out.println(value);
System.out.println(this.value);
System.out.println(localValue);
System.out.println(this.localValue); // コンパイルエラー
}
}
という風に、ローカル変数には this というキーワードを「付けられません」。
フィールドの場合は「付けても付けなくても意味は変わりません」。
しかし、暗黙的に「フィールドには this を付けるものだ」という考えを持っている人もいるようです。
ここで、ClassA と、それを拡張(extends)した ClassB を考えてみます。
class ClassA {
protected int value = 10;
}
class ClassB extends ClassA {
protected int value = 20;
public void func() {
System.out.println(value);
System.out.println(this.value);
System.out.println(super.value);
}
}
実行結果は以下のようになります。
20 20 10
先程と同じように、thisは付けても付けなくても結果は一緒です。
しかし、super は結果が異なります。super. とは「一つ上位のクラスで定義されたフィールドを参照」するためのキーワードです。
つまり、3行目は ClassA.value を表示しているわけです。
別の例を挙げてみます。
class ClassA {
protected int value = 10;
}
class ClassB extends ClassA {
public void func() {
System.out.println(value);
System.out.println(this.value);
System.out.println(super.value);
}
}
先程の例と異なるのは、ClassBに value が定義されていないという点だけです。
さて、結果は次のようになります。
10 10 10
ClassBには value が定義されていないので、
キーワード無しの value は ClassA.value を参照します。
それと同じように、this.value も ClassA.value を参照するのです。
「どこが this じゃコラ」というお怒りの声ももっともです(笑)。
でもこれが、Javaの仕様です。
thisと書いてあるからといって、同一クラス内にそのフィールドがあるとは限らない のです。
これは非常に紛らわしいですね。
繰り返しになりますが、this.value と value は「全く同じ」なのです。
という参照経路を辿ります。一方、super.value はと言うと…
という風に、自クラスのフィールドを対象外にするだけです。
つまり、superと書いてあるからといって、一つ上のクラスにそのフィールドがあるとは限らない のです。
ですから、「自クラスにあるこのフィールドを参照したい」だとか
「あの上位クラスにあるフィールドを参照したい」だとかいう適切な指示を
Javaコンパイラに出すのは仕様上無理という事です。
これを考えれば、同一名のprotectedフィールドは継承クラス内に持つべきではありません。
もう一歩踏み込んで考えると、
protected のフィールドは一切持たないようにするのが良いでしょう。
こうすれば、他クラスの事を考えずにフィールド名を決定することができます。
ただし、そのフィールドに Getter / Setter を定義しようとしているならば
やはり継承クラス内に同一名のフィールドは持たない方が良いのです。
this. を使えば、確かにその変数がフィールドだという事が明確にわかります。
しかし、たったそれだけなのです。
例えば、そのフィールドをリファクタリングによって上位クラスに移動させたら
this. という表記はかえって紛らわしくなります。
class ClassA {
protected int value = 10; // ClassBにあったフィールドをこちらに移動
}
class ClassB extends ClassA (
// protected int value = 10; // もともとはここにあったフィールドを移動
public void func() {
System.out.println(this.value); // 実際には super. としなければならない
}
}
何と言っても「コードを余計に長くする」という点は、耐えがたいデメリットです。
int total = this.first + this.second; int total = first + second;
this. を付けるとコードが長くなり、それによって可読性が落ちます。
可読性が落ちると保守性も低下します。
別にフィールドだという事が明確にわかったからって、大したメリットではないのです。
最近のIDEは、フィールドをわかりやすいように色分けしてくれるんですから。
だから、僕は this を付けたくないのです。