为什么Runtime binding(运行时绑定)无法在compile time(编译期)完成?
为什么Java编译器无法在编译期确定运行时绑定的方法实现
你给出的示例属于非常简单的静态可推导场景,但Java的方法重写绑定规则是全局统一的,不会因为场景简单就做特例处理,核心原因有三个:
1. 多数多态场景下实际对象类型编译期完全无法确定
你举的例子是直接在代码里写死了Animal a = new Dog(),但实际开发中绝大多数多态场景的实际类型是运行时才会确定,编译阶段根本推导不出来,比如:
- 根据运行时输入动态生成对象:
Animal getAnimalByUserInput(){ Scanner sc = new Scanner(System.in); String type = sc.nextLine(); if("dog".equals(type)) return new Dog(); else if("cat".equals(type)) return new Cat(); else return new Animal(); } // 调用时编译期完全无法知道返回的实际对象类型 Animal a = getAnimalByUserInput(); a.eat();
- 调用第三方依赖返回的父类引用:如果引用对象是二方库、三方包返回的父类实例,编译期看不到依赖的运行逻辑,不可能推导实际类型。
2. Java支持运行时动态加载类
Java的类加载机制是动态的,运行时可以加载编译阶段完全不存在的子类。比如你编译代码的时候只有Dog、Cat两个Animal的子类,运行时完全可以动态加载一个新的Tiger extends Animal的子类赋值给Animal类型的引用,编译器不可能预知运行时会加载什么新的子类。
3. 特例化规则会破坏语言语义一致性
如果Java对简单场景做静态绑定,复杂场景做动态绑定,会导致同一段代码的行为出现不可预期的差异:比如你现在写的Animal a = new Dog();a.eat();编译期绑定到Dog的eat方法,后面你把实例化逻辑抽到其他方法里,同一段a.eat()就变成了运行时绑定,行为可能发生变化,会大幅提升代码维护成本,也违背了多态的设计初衷。
你给出的示例这种固定类型的调用,JVM的即时编译(JIT)阶段会做优化,运行时会直接把方法调用绑定到对应的实现,消除虚方法调用的开销,性能和静态绑定几乎没有差别。
内容的提问来源于stack exchange,提问作者Saurabh Dhage
相关产品推荐
相关产品推荐

