thisはメソッドとフィールドで微妙に違う件
JavaScriptのthisではまった - No Programming, No LifeとJava の this について - SiroKuro Pageの話。
Javaでは動的に付けたり外したりできず、class宣言時にすべてが決まってしまうから、thisが参照するインスタンスは固定的にできるわけですね。
JavaScriptのthisではまった - No Programming, No Life実はこれはダウト。Java では継承があるから、事実上 this に入るクラスを静的に決定することは不可能。そして final クラスにしたとしても、どのインスタンスが入るかを決めるのは難しいわけです。
Java の this について - SiroKuro Page
元記事に対して「どのオブジェクト上で走るかの話で、javaのthisも同じっちゃ同じ。 」ってブクマコメントを残したけど、中途半端だったから調べてみた。
結論としては、メソッドとフィールドの扱いは違うっぽい。
- メソッドを参照する場合、thisは実行時のインスタンスを指す。
- フィールドを参照する場合、thisは定義時のフィールドを指す。
つまり、フィールドは性的に…じゃなくて静的に決定するらしい。
検証
- Hoge#toString()の中で使われるthisは、SubHogeクラスのインスタンス上で実行しても、Hogeクラスインスタンスのnameフィールドを示す。SubHogeクラスインスタンスのnameフィールドではない。
- subHogeをSubHogeクラスとして扱う場合とHogeでキャストした場合とで、subHoge.nameの示す値が自然に変わってたりする。
public class Hoge { public String name = "Hoge"; public void foo() { System.out.println(this.toString()); } @Override public String toString() { return this.name; } public static class SubHoge extends Hoge { public String name = "SubHoge"; } public static void main(String...args) { //当然のケース。 Hoge hoge = new Hoge(); hoge.foo(); //prints "Hoge". System.out.println(hoge.name); //サブクラスのオブジェクトの動作。 SubHoge subHoge = new SubHoge(); subHoge.foo(); //prints "Hoge". System.out.println(subHoge.name); //prints "SubHoge". System.out.println(((Hoge)subHoge).name); //prints "Hoge". } }
普通はフィールドはオーバライドしないと思うけど、言語仕様上は可能なわけで。微妙に気をつけようと思いました。
追記
実行時に,参照される実際のオブジェクトのクラスではなく,その Primary 式の型だけが,使用するフィールドを決定する際に使用されることに注意すること。
Java¾êKè ®