minimize

thisって何ですか?
という質問については、申し訳ありませんが他のページを参照して下さい。
ここでは、Javaで this を使うことによるメリット・デメリットについて考えてみます。

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 を付けるものだ」という考えを持っている人もいるようです。

thisとsuper

ここで、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 を表示しているわけです。

あいまいなthisとsuper

別の例を挙げてみます。

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.valuevalue は「全く同じ」なのです。

  1. 自クラスにそのフィールドが定義されていればそれを参照

  2. 定義されていなければ、一つ上の上位クラスにフィールドが定義されていればそれを参照

  3. そこにも定義されていなければ、見つかるまで上位のクラスを探していって…それを参照

という参照経路を辿ります。一方、super.value はと言うと…

  1. 一つ上の上位クラスにフィールドが定義されていればそれを参照

  2. そこにも定義されていなければ、見つかるまで上位のクラスを探していって…それを参照

という風に、自クラスのフィールドを対象外にするだけです。
つまり、superと書いてあるからといって、一つ上のクラスにそのフィールドがあるとは限らない のです。

ですから、「自クラスにあるこのフィールドを参照したい」だとか
「あの上位クラスにあるフィールドを参照したい」だとかいう適切な指示を
Javaコンパイラに出すのは仕様上無理という事です。

これを考えれば、同一名のprotectedフィールドは継承クラス内に持つべきではありません。
もう一歩踏み込んで考えると、
protected のフィールドは一切持たないようにするのが良いでしょう。
こうすれば、他クラスの事を考えずにフィールド名を決定することができます。
ただし、そのフィールドに Getter / Setter を定義しようとしているならば
やはり継承クラス内に同一名のフィールドは持たない方が良いのです。

thisのメリット・デメリット

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 を付けたくないのです。

[コメント(0)]