对Java方法内部使用this访问成员变量的深入理解

一直以为Java里面的this是指当前[color=red]真实[/color]调用对象,今天突然发现不是那么回事。
有两个注意点:
1、在Java中,直接访问域或静态成员(包括静态方法和静态成员变量)永远都是前期绑定。
2、在Java中,访问方法是后期绑定。
不过这样容易出现一个疑点:若B类继承A类,A类和B类都包含一个public int i 这样的域,如果在A类中有一个方法通过this访问域,而这个方法的调用者却是B类的对象,那么访问到的域到底是A类中的i还是B类中的i呢?请看代码:
package com.wangf.test.javasuper;

class A {

public int i = 100;

public void p() {
System.out.println(this.getClass().getName());
System.out.println(this.i);
}
}

class B extends A {

public int i = 200;

}

public class Test {

public static void main(String[] args) {
B b = new B();
b.p();
}
}

[color=blue]打印结果为:
com.wangf.test.javasuper.B
100[/color]
明显可看到,此时p()方法的调用者是B类的对象,然后i的值却不是200,而是100;
[size=large][color=red]这就说明了在方法内部通过this访问的域永远都是:方法所在的类的域,我们只需要关注调用的方法是属于哪个类的就行了![/color][/size]
[color=blue]在上例中,虽然是通过B类的对象来调用p()方法,但p()方法是B类通过继承得到的,也就是说此时p()方法是属于A类的,所以访问到的i仍然是A类中的成员i[/color]

再来看看当p()方法在B类中被重写后的情况:
package com.wangf.test.javasuper;

class A {

public int i = 100;

public void p() {
System.out.println(this.getClass().getName());
System.out.println(this.i);
}
}

class B extends A {

public int i = 200;

@Override
public void p() {
System.out.println(this.getClass().getName());
System.out.println(this.i);
}
}

public class Test {

public static void main(String[] args) {
B b = new B();
b.p();
}
}

[color=blue]打印结果为:
com.wangf.test.javasuper.B
200[/color]
[color=blue]可以看出,此时访问到的i变量,已经是B类中的i变量了,因为此时通过B类的对象调用的p()方法,是B类覆盖过后的,也就是说这个方法已经“属于”B类,所以访问到的i是B类的成员变量i[/color]

[color=red]插播一个当多态发生时的例子:[/color]
将Test类修改如为:
public class Test {

public static void main(String[] args) {
A a = new B();
System.out.println(a.i);
a.p();
}
}

[color=blue]打印结果为:
100
com.wangf.test.javasuper.B
200
可以看到:直接通过a.i访问的域i和通过a.p()方法访问的域i并不是同一个i,因为在Java中,直接访问域永远都是编译前期绑定,即在编译时则通过引用a的类型A找到了成员变量i,所以这个i等于100;而方法访问则是运行期动态绑定,也就是说在运行时找到引用a的真实类型B,然后访问B的方法p(),所以p()方法此时“属于”B,所以在p()方法中打印出的i等于200
[/color]

[size=large][color=red]以上的讨论都是指通过this访问域,那么通过this访问方法呢?使用super访问父类的方法呢?
答案是:访问方法永远都会查找真实的调用对象,我们需要关注被调用的方法到底“属于”哪个类![/color][/size]
package com.wangf.test.javasuper;

class A {

public int i = 100;

public void q() {
System.out.println("A类中的q()");
System.out.println(this.i);
}

public void p() {
System.out.println(this.getClass().getName());
System.out.println(this.i);
this.q();
}
}

class B extends A {

public int i = 200;

// public void q() {
// System.out.println("B类中的q()");
// System.out.println(this.i);
// }

@Override
public void p() {
super.p();
}
}

public class Test {

public static void main(String[] args) {
B b = new B();
b.p();
}
}

[color=blue]打印结果为:
com.wangf.test.javasuper.B
100
A类中的q()
100
分析:通过B类的对象调用p()方法,在p()方法内部通过super.p()调用A类的p()方法,所以调用对象是B,此时p()方法是“属于”A的,所以访问到的i等于100,然后再通过this.q()访问q方法,由于B类中此时没有q()方法,所以访问的是A类中的q()方法(继承),所以打印出了这样的结果
[/color]


若把B类中的注释去掉,可以得到结果如下:
[color=blue]com.wangf.test.javasuper.B
100
B类中的q()
200
因为此时B类已经重写了q()方法,所以访问的是B类中的q()方法,所以i也是B类中的i。
[/color]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值