一直以为Java里面的this是指当前 真实调用对象,今天突然发现不是那么回事。
有两个注意点:
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();
- }
- }
打印结果为:
com.wangf.test.javasuper.B
100
明显可看到,此时p()方法的调用者是B类的对象,然后i的值却不是200,而是100;
这就说明了在方法内部通过this访问的域永远都是:方法所在的类的域,我们只需要关注调用的方法是属于哪个类的就行了!
在上例中,虽然是通过B类的对象来调用p()方法,但p()方法是B类通过继承得到的,也就是说此时p()方法是属于A类的,所以访问到的i仍然是A类中的成员i
再来看看当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();
- }
- }
打印结果为:
com.wangf.test.javasuper.B
200
可以看出,此时访问到的i变量,已经是B类中的i变量了,因为此时通过B类的对象调用的p()方法,是B类覆盖过后的,也就是说这个方法已经“属于”B类,所以访问到的i是B类的成员变量i
插播一个当多态发生时的例子:
将Test类修改如为:
- public class Test {
- public static void main(String[] args) {
- A a = new B();
- System.out.println(a.i);
- a.p();
- }
- }
打印结果为:
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访问父类的方法呢?
答案是:访问方法永远都会查找真实的调用对象,我们需要关注被调用的方法到底“属于”哪个类!
- 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();
- }
- }
打印结果为:
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。