Java中字段不参与多态

字段不参与多态

学习到这里的时候很好玩,记录一下。

直接来个例子,如果你能答对,也就不用看这这篇文章了。

public class FieldHasNoPolymorphic {
    static class Father{
        public int money = 1;

        public Father(){
            System.out.println("father`s constructor is invoked by:" + this);
            money = 2;
            showMeTheMoney();
        }

        public void showMeTheMoney(){
            System.out.println("DynamicDispatch Result: I am Father,i have $" + money);
        }
    }

    static class Son extends Father{
        public int money = 3;

        public Son(){
            money = 4;
            showMeTheMoney();
        }
        
        @Override
        public void showMeTheMoney(){
            System.out.println("DynamicDispatch Result: I am Son,i have $" + money);
        }
    }

    public static void main(String[] args) {
        Father guy = new Son();
        System.out.println("Result: guy has $" + guy.money);
    }

}

Father guy = new Son(); guy 的静态类型为 Father,实际类型为 Son。

1.new Son(); 对应的字节码指令:

  1. new :为 son 对象在堆中开辟内存空间,将对象引用压入操作数栈顶
  2. dup :赋值栈顶元素再次压栈
  3. invokespecial :调用 Son 的实例化方法( < init >() 方法),实例化 son 对象(为字段赋值 + 执行实例代码块 + 调用无参构造方法)。再传入一个 son 对象作为实例化方法中的 this 关键字

创建对象的过程这里暂不讨论。

2.进入 Son 对象实例化方法(为字段赋值 + 执行实例代码块 + 调用无参构造方法):

public Son() {
    this.money = 3;
    this.money = 4;
    this.showMeTheMoney();
}

父类有无参构造的情况下,子类构造方法的第一行默认是 super(); 即:

public Son() {
    super();
    this.money = 3;
    this.money = 4;
    this.showMeTheMoney();
}

super() 对应的字节码指令为:

 0: aload_0
 1: invokespecial #1                  // Method clazz/dynamicDispatch/FieldHasNoPolymorphic$Father."<init>":()V

Son 类无参构造方法的 0 号变量槽存储了 son 对象引用。通过 aload_0 指令把 son 对象压入栈顶,传入父类的无参构造方法作为方法中的 this 关键字。

3.进入父类的实例化方法(为字段赋值 + 执行实例代码块 + 调用无参构造方法):

public FieldHasNoPolymorphic$Father() {
    super(); // Object <init>()
    System.out.println("father`s constructor has invoked by:" + this);
    this.money = 2;
    this.showMeTheMoney();
    this.test1();
}
  1. 调用 Object 类的无参构造方法

  2. 输出 this 关键字代表的 son 对象的引用。

    fathers constructor is invoked by:clazz.dynamicDispatch.FieldHasNoPolymorphic$Son@4554617c

  3. 为 money 字段赋值。由于字段不参与多态,所以是给 Father 类中的 money 字段赋值为 3。

  4. 调用 showMeTheMoney() 方法,由于在以上代码中此方法存在多种版本,所以这个方法是虚方法,需要在运行期间动态判断此方法的版本是 Father 类的还是 Son 类的。对应的字节码指令为 invokevitrual。

    执行 invokevitural 指令前,将 this 关键字对应的对象压入操作数栈顶,判断该对象的实际类型,为 Son。

    执行 invokevitural 指令,调用 Son 类中的 showMeTheMoney() 方法。由于此时 Son 类还没有来得及初始化,所以输出 "DynamicDispatch Result: I am Son,i have $0"

4.父类实例化方法调用完成,返回子类实例化方法继续执行:

public Son() {
    super();
    this.money = 3; <——
    this.money = 4;
    this.showMeTheMoney();
}

为 Son 类的 money 字段赋值 4 。调用虚方法 showMeTheMoney()前进行方法分派,确定 showMeTheMoney() 为 Son 类方法。输出 "DynamicDispatch Result: I am Son,i have $4"

5.Son 类实例化方法执行完毕,返回 main 方法继续执行:

System.out.println("Result: guy has $" + guy.money);

因为字段不参与多态,所以在编译期间编译器可以通过 guy 的静态类型找到目标字段的值。而且此时 Father 类以及完成初始化,money 字段值为 2,输出 "Result: guy has $2"

end…

  • 9
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值