关于Java动态绑定的疑惑
阿神
阿神 2017-04-17 11:26:39
[Java讨论组]

以下内容有选择地摘自《Java编程思想》:

enum Note {
    MIDDLE_C, C_SHARP, B_FLAT
}

class Instrument {
    public void play(Note n) {
        System.out.println("Instrument.play() " + n);
    }
}

class Wind extends Instrument {
    @Override
    public void play(Note n) {
        System.out.println("Wind.play() " + n);
    }
}

class Brass extends Instrument {
    @Override
    public void play(Note n) {
        System.out.println("Brass.play() " + n);
    }
}

public class Music {
    public static void tune(Instrument i) {
        i.play(Note.B_FLAT);
    }

    public static void main(String[] args) {
        Wind flute = new Wind();
        tune(flute);
    }
}

之后,书中提到:

请观察一下 tune() 方法,它接受一个 Instrument 引用。那么在这种情况下,编译器怎样才能知道这个 Instrument 引用指向的是 Wind 对象,而不是 Brass 对象呢?实际上,编译器无法得知。
上述程序之所以令人迷惑,主要是因为前期绑定。因为,当编译器只有一个 Instrument 引用时,它无法知道究竟调用哪个方法才对。(这句话要怎么理解?)

所以,我的疑问是:既然 tune() 内接的是 Wind 对象 flute,那么它就应该知道调用 Wind.play() 方法,而不是调用 Instrument.play() 方法或 Brass.play() 方法。如果 Wind 没有覆盖 play() 方法,那么最终应该调用基类 Instrument.play() 方法。于是书中所说的令人迷惑的地方在哪里?还有,引用中的那句话要怎么理解?

阿神
阿神

闭关修行中......

全部回复(3)
PHP中文网

试想一下,如果该class被其它代码import,那么tune方法接受的参数的类型还一定是Wind吗?
所以,编译器其实不能确定tune方法接受的参数为Wind类型,只能确定它是代码中写的Instrument类型。JVM提供了invokevirtual指令,用于实现这个polymorphic调用。如果编译器换成invokespecial Wind.play,那这段代码的语义就不一样了。

你可能会想,如果将tune方法标记成private,是不是编译器就能够分析出tune方法始终只接受一个Wind类型的参数,期望它能将其优化成invokespecial,这样效率更高呢?其实程序员不用关心这个的,JVM会对invokevirtual自动作优化,不会每次调用都去查找是调用子类还是父类方法的。

迷茫

Java中属性绑定到类型,方法绑定到对象.

编译时期,系统并不清楚变量是哪个类的实例。具体调用哪个类的方法 运行时才能决定。

大家讲道理

实际上有些情况下,编译器是可以确定的,比如这个例子

public static void main(String[] args) {
      String str = new String();
      final Caller callerSub = new SubCaller();
      callerSub.call(str);
}

但是为了安全和一致性,索性就交给了动态绑定。具体可以参考Java中的静态绑定和动态绑定

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责申明 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送
PHP中文网APP
随时随地碎片化学习
PHP中文网抖音号
发现有趣的

Copyright 2014-2025 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号