Java中Dynamic Binding、Overriding/Overloading调用问题解惑
Java方法绑定与继承问题解答
public abstract class Vector{ public abstract double norm(); } public class PlanarVector extends Vector { protected final double x; protected final double y; public PlanarVector(double x, double y){ this.x=x; this.y=y; } public double norm(){ return Math.sqrt(x*x+y*y); } public PlanarVector sum(PlanarVector v){ return new PlanarVector(x+v.x, y+v.y); } public String toString(){ return "x=" + x + " y=" + y; } } public class SpaceVector extends PlanarVector { protected final double z; public SpaceVector(double x, double y,double z){ super(x,y); this.z=z; } public double norm(){ return Math.sqrt(x*x + y*y + z*z); } public SpaceVector sum(SpaceVector v){ return new SpaceVector(x+v.x, y+v.y, z+v.z); } public String toString(){ return super.toString() + " z=" + z; } } public class TestVector { public static void main ( String[] args ) { Vector v0 ; PlanarVector v1 , v2 ; SpaceVector v3 , v4 ; v1 = new PlanarVector ( 3 , 4 ) ; v0 = v1 ; v2 = new SpaceVector ( 2 , 3 , 6 ) ; v3 = new SpaceVector ( 2 , 1 , 0 ) ; v4 = v3 ; System.out.println(v1.sum(v2)) ; //expected output: x=5 y=7 realoutput: x=5 y=7 (v1 can only use PlanarVectorMethods because its dynamic and static type is PlanarVector) System.out.println(v2.sum(v1)) ; //expected output: x=5 y=7 realoutput: x=5 y=7 System.out.println(v2.sum(v3)) ; //expected output: 'x=4 y=4 z=6' realoutput: 'x=4 y=4' System.out.println(v3.sum(v2)) ; //expected output: 'x=4 y=4 z=6' realoutput: 'x=4 y=4' System.out.println(v3.sum(v4)) ; System.out.println(v1.norm()) ; System.out.println(v2.norm()) ; //expected output: sqrt(13) realoutput: 7 } }
问题解答
1. 为何v2.sum(v3)未调用SpaceVector类的sum方法?
Java里方法重载是静态绑定,编译阶段就确定要调用的方法。v2的静态类型是PlanarVector,编译器只会查找PlanarVector及其父类中定义的sum方法。SpaceVector的sum方法参数是SpaceVector,这属于重载而非重写,编译器不认子类新增的重载方法,所以编译时绑定到PlanarVector的sum(PlanarVector),运行时自然不会调用SpaceVector的sum。
2. 为何v3.sum(v2)也未调用SpaceVector类的sum方法?
v3的静态类型是SpaceVector,但v2的静态类型是PlanarVector。方法重载匹配看参数的静态类型,而非实际动态类型。SpaceVector的sum(SpaceVector)要求参数是SpaceVector类型,而v2的静态类型是PlanarVector,编译器无法确定v2实际是SpaceVector实例,因此会匹配到从PlanarVector继承来的sum(PlanarVector)方法,而非SpaceVector自己的sum方法。
3. 为何v2.norm()又调用了SpaceVector类的norm方法?
norm()是重写方法:SpaceVector的norm和PlanarVector的norm方法签名完全一致(方法名、参数列表、返回值均匹配)。Java中重写方法是动态绑定,运行时根据对象的实际类型(动态类型)调用对应方法。v2的动态类型是SpaceVector,所以运行时执行SpaceVector的norm实现。
4. 父类引用指向子类实例时,为何无法调用子类独有方法,但可调用重写后的子类实现方法?
- 无法调用子类独有方法:编译阶段编译器只校验引用的静态类型,父类中没有子类独有方法的定义,编译器会直接报错,无法进入运行阶段。
- 可调用重写后的子类实现:重写方法采用动态绑定,运行时会根据对象的实际类型(动态类型)调用子类的实现,不管引用的静态类型是什么,只要实际对象是子类实例,就会执行子类的重写逻辑。
内容的提问来源于stack exchange,提问作者Mateusz
相关产品推荐
相关产品推荐

