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

一直以为Java里面的this是指当前 真实调用对象,今天突然发现不是那么回事。
       有两个注意点:
1、在Java中,直接访问域或静态成员(包括静态方法和静态成员变量)永远都是前期绑定。
2、在Java中,访问方法是后期绑定。
       不过这样容易出现一个疑点:若B类继承A类,A类和B类都包含一个public int i 这样的域,如果在A类中有一个方法通过this访问域,而这个方法的调用者却是B类的对象,那么访问到的域到底是A类中的i还是B类中的i呢?请看代码:
Java代码   收藏代码
  1. package com.wangf.test.javasuper;  
  2.   
  3. class A {  
  4.       
  5.     public int i = 100;  
  6.       
  7.     public void p() {  
  8.         System.out.println(this.getClass().getName());  
  9.         System.out.println(this.i);  
  10.     }  
  11. }  
  12.   
  13. class B extends A {  
  14.       
  15.     public int i = 200;   
  16.       
  17. }  
  18.   
  19. public class Test {  
  20.   
  21.     public static void main(String[] args) {  
  22.         B b = new B();  
  23.         b.p();  
  24.     }  
  25. }  

打印结果为:
com.wangf.test.javasuper.B
100

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

再来看看当p()方法在B类中被重写后的情况:
Java代码   收藏代码
  1. package com.wangf.test.javasuper;  
  2.   
  3. class A {  
  4.       
  5.     public int i = 100;  
  6.       
  7.     public void p() {  
  8.         System.out.println(this.getClass().getName());  
  9.         System.out.println(this.i);  
  10.     }  
  11. }  
  12.   
  13. class B extends A {  
  14.       
  15.     public int i = 200;   
  16.       
  17.     @Override  
  18.     public void p() {  
  19.         System.out.println(this.getClass().getName());  
  20.         System.out.println(this.i);  
  21.     }  
  22. }  
  23.   
  24. public class Test {  
  25.   
  26.     public static void main(String[] args) {  
  27.         B b = new B();  
  28.         b.p();  
  29.     }  
  30. }  

打印结果为:
com.wangf.test.javasuper.B
200

可以看出,此时访问到的i变量,已经是B类中的i变量了,因为此时通过B类的对象调用的p()方法,是B类覆盖过后的,也就是说这个方法已经“属于”B类,所以访问到的i是B类的成员变量i

插播一个当多态发生时的例子:
将Test类修改如为:
Java代码   收藏代码
  1. public class Test {  
  2.   
  3.     public static void main(String[] args) {  
  4.         A a = new B();  
  5.         System.out.println(a.i);  
  6.         a.p();  
  7.     }  
  8. }  

打印结果为:
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


以上的讨论都是指通过this访问域,那么通过this访问方法呢?使用super访问父类的方法呢?
答案是:访问方法永远都会查找真实的调用对象,我们需要关注被调用的方法到底“属于”哪个类!

Java代码   收藏代码
  1. package com.wangf.test.javasuper;  
  2.   
  3. class A {  
  4.       
  5.     public int i = 100;  
  6.       
  7.     public void q() {  
  8.         System.out.println("A类中的q()");  
  9.         System.out.println(this.i);  
  10.     }  
  11.       
  12.     public void p() {  
  13.         System.out.println(this.getClass().getName());  
  14.         System.out.println(this.i);  
  15.         this.q();  
  16.     }  
  17. }  
  18.   
  19. class B extends A {  
  20.       
  21.     public int i = 200;   
  22.       
  23. //  public void q() {  
  24. //      System.out.println("B类中的q()");  
  25. //      System.out.println(this.i);  
  26. //  }  
  27.       
  28.     @Override  
  29.     public void p() {  
  30.         super.p();  
  31.     }  
  32. }  
  33.   
  34. public class Test {  
  35.   
  36.     public static void main(String[] args) {  
  37.         B b = new B();  
  38.         b.p();  
  39.     }  
  40. }  

打印结果为:
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()方法(继承),所以打印出了这样的结果



若把B类中的注释去掉,可以得到结果如下:
com.wangf.test.javasuper.B
100
B类中的q()
200
因为此时B类已经重写了q()方法,所以访问的是B类中的q()方法,所以i也是B类中的i。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值