【问题标题】:Dynamic Binding and Overriding/Overloading in javajava中的动态绑定和覆盖/重载
【发布时间】:2023-01-08 03:02:03
【问题描述】:
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

   

    }
}

有人能解释一下为什么“System.out.println(v2.sum(v3))”中的 v2.sum(v3) 不使用子类方法吗? 我知道 v2 的静态类型是 PlanarVector 但它的动态类型是 SpaceVector System.out.println(v3.sum(v2)) 也是如此,v3 的静态和动态类型是 SpaceVector,v2 在这里被认为是 planarVector?为什么?! 这次最后一个 System.out.println(v2.norm()) 将 v2 视为 SpaceVector ... 发生了什么?! 我还有最后一个问题,超类不能使用子类方法,即使它是子类的实例,对吗?如果该方法是子类中的重写方法会发生什么,为什么超类现在可以使用它(并使用子类实现)?

我在问一个关于 Java 基础知识的问题,希望通过示例获得简单明了的答案。

【问题讨论】:

  • “有人能解释一下为什么“System.out.println(v2.sum(v3))”中的 v2.sum(v3) 不使用子类方法”——因为子类方法不覆盖sum,它过载它,因为参数类型不同。我强烈建议您在尝试覆盖方法时使用 @Override 注释 - 这样编译器可以在您实际上没有这样做时告诉您......

标签: java inheritance


【解决方案1】:

方法
SpaceVector sum (SpaceVector)
在 SpaceVector 中不是 PlanarVector sum (PlanarVector)
在 PlanarVector 中,但只是一个重载。

这两种方法都存在于 SpaceVector 中。 它不是覆盖,因为签名不同(传递的参数不是同一类型)。

其次,Java 不通过使用简单的虚拟表实现多参数分派,而仅实现单参数分派。很明显,这意味着它只查看第一个参数来动态决定调用哪个方法,并且 在 Java 中,(非静态)方法的第一个参数总是隐式的 this 引用。 this 引用基本上决定了在哪个方法中查看虚拟表。 其他参数总是在编译时解析,从不动态解析。 一些语言实现了多参数分派,但 Java 没有。

如果将这两种信息放在一起,您就可以理解为什么实际调用的方法不是您期望的方法: 您传递了一个声明类型为 PlaneVector 的对象,因此调用的方法是 PlaneVector sum(PlaneVector)。编译器不知道,实际上无法知道您是否有对 PlaneVector 或子类的引用。

尝试更改 v2 和 v3 的声明,您将看到不同之处。也可以尝试使用 var 关键字并观察会发生什么。自己试验一下就明白了,挺有意思的。

如果您希望您的代码像多参数分派一样工作,您将需要实现众所周知的访问者模式。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-21
    • 2013-04-05
    • 2022-01-10
    相关资源
    最近更新 更多