java-this和super

 1 public class Parent {
 2   protected String name = "parent";
 3   public Parent() {
 4     System.out.println(this.name);//parent
 5     fun();//son name: son
 6   }
 7 
 8   protected void fun() {
 9     System.out.println("parent name: " + name);
10   }
11 }
12 
13 public class Son extends Parent{
14   protected String name = "son";
15   public Son() {
16   }
17   
18   protected void fun() {
19     System.out.println("son name: " + name);
20   }
21 }

实例化一个Son对象,会发现输出

parent
son name: son

也就是说Parent的构造函数中,this.name的this为Parent,this.fun()的this为Son,这是为什么呢?其实Parent中的this始终都是Son,但由于字段的取值取决于实例的静态类型,而不是向invokevirtual那样取决于实际类型,我们都知道java方法的第一个参数永远是this(除了静态方法,this的作用就是连接实例对象,从而操作实例字段、实例方法,而静态方法并不会与某个实例关联,故静态方法不会传入this,也就不能操作实例字段、实例方法了),当Son构造器调用Parent构造器时传入的this,一定经过了类似向上转型的过程(猜测是这样),从而this的静态类型在Parent看来是Parent类型的。

这就解释了为什么在Parent中的this.name是Parent的字段,那么this.fun()是Son的怎么解释呢?这就是invokevirtual的威力了,invokevirtual会在运行时动态判断调用者的实际类型,从而决定调用方法的版本。

 1 public class Parent {
 2   protected String name = "parent";
 3 
 4   protected void fun() {
 5     System.out.println("parent name: " + name);
 6     fun();
 7   }
 8 }
 9 
10 public class Son extends Parent{
11   protected String name = "son";
12   private boolean flag = false;
13   
14   protected void fun() {
15       if(!flag) {
16           flag = true;
17           super.fun();
18       }else{
19           System.out.println("son name: " + name);
20       }
21   }
22 }

再来看上面这个例子,new Son().fun()一定是输出

parent name: parent
son name: son

因为super.fun()会传入向上转型的this,从而在进行字段输出时输出parent,调用方法fun()时又会使用invokevirtual指令寻找实际类型,所以会调用Son的fun()方法,而此时传入的this又会向下转型为Son,故输出字段为son。

原文地址:https://www.cnblogs.com/holoyong/p/7510398.html