Java - 父 class 正在调用子 class 的方法?

Java - parent class is calling a method from a child class?

抱歉,我对编码还是个新手,可能没有掌握所有术语。希望您仍然能理解我的问题。我想要得到的输出是:

"Cost for Parent is: 77.77"
"Cost for Child is: 33.33"

但是,我得到这个:

"Cost for Parent is: 33.33"
"Cost for Child is: 33.33"

谁能明白为什么?下面是我的代码的简化版本,但其背后的逻辑保持不变...

public class Parent{
    public double calculateCost(){
        return 77.77;
    }

    @Override
    public String toString(){
        return "Cost for Parent is: " + calculateCost();
    }
}

public class Child extends Parent{
    @Override
    public double calculateCost(){
        return 33.33;
    }

    @Override
    public String toString(){
        return super.toString() + "\nCost for Child is: " + calculateCost();
    }

    public static void main(String[] args){
        Child child1 = new Child();
        System.out.println(child1.toString());
    }
}

在我看来,子 class 中的 toString() 应该调用父 class 中的 toString() (因此,父 class 中的 calculateCost() ) 然后用 Child 的 calculateCost() 添加到它。我猜 super.toString() 中的 super 不适用于它包含的 calculateCost() 。

另外,我知道我可以通过像这样在 Child class 中编写 toString() 来绕过它:

    @Override
    public String toString(){
        return "Cost for Parent is: " + super.calculateCost() + "\nCost for Child is: " + calculateCost();
    }

但重点是我不想重复代码,我宁愿添加到我覆盖的先前 toString() 方法中。请帮助或指导我(不确定我应该用谷歌搜索什么...)谢谢!

请注意,您是在 toString 方法中调用 calculateCost() 。因此 child 的 calculateCost() 被调用。您可以考虑使用 Child 的 toString 函数,如下所示。

class Parent{
public double calculateCost(){
    return 77.77;
}

@Override
public String toString(){

    return "Cost for Parent is: " + calculateCost();
}
}

class Child extends Parent{
@Override
public double calculateCost(){
    return 33.33;
}

@Override
public String toString(){
    return "Cost for Parent is: " + super.calculateCost() + "\nCost for 
Child is: " + calculateCost();
}
}

calculateCostChild class 中被覆盖。因此,当从 Child 调用 super.toString() 时,super.toString() 中的 calculateCost() 将是 ChildcalculateCost.

您必须将 super.calculateCost() 显式放入 Child class 才能调用 ParentcalculateCost

我认为为此您可以做的最好的事情是使用调试模式,这样您可以更好地理解它是如何工作的。阅读您的代码后,我了解您希望它如何 运行。

但是我觉得你实现@Override注解的方式有问题。

的意思

@Override annotation is to implement a new method that had been literally overriding from the parent class.

在这种情况下,不会使用父项 class 的 public double calculateCost(),因为您覆盖了子项 class 的计算成本。

希望我已经解释清楚了。但是在这种情况下,您需要做的是研究更多 @Override 并了解它是如何工作的。

您最好能创建一个父对象和一个子对象。从 child 的 toString 方法中删除 super.toString,那么你会得到相同的结果:

public class Parent{
    double cost = 77.77;
    public double calculateCost(){
        return cost;
    }

    @Override
    public String toString(){
        return "Cost for Parent is: " + this.calculateCost();
    }

}

public class Child extends Parent{
    @Override
    public double calculateCost(){
        return 33.33;
    }

    @Override
    public String toString(){
        return "\nCost for Child is: " + calculateCost();
    }

    public static void main(String[] args){
        Parent parent = new Parent();
        Child child1 = new Child();
        System.out.println(parent.toString() + child1.toString());
    }
}

打印:

Cost for Parent is: 77.77
Cost for Child is: 33.33

这是 java 中的向上转换。
如果subclass 和parent class 都有一个方法.then 将执行subclass。如果不是,则将执行 parent class,尽管您调用 toString 方法包括 calculateCost

你的parentclass中的方法,但实际上会执行子class中的calculateCost方法。

您可以修改您的代码如下:

Parent Class

public class Parent{
    public double calculateCostParent(){
        return 77.77;
    }


    public String toString(){
        return "Cost for Parent is: " + calculateCostParent();
    }
}

Child Class

public class Child extends Parent{

    public double calculateCost(){
        return 33.33;
    }

    @Override
    public String toString(){
        return super.toString() + "\nCost for Child is: " + this.calculateCost();
    }

    public static void main(String[] args){
        Child child1 = new Child();
        System.out.println(child1.toString());
    }
}

输出

Cost for Parent is: 77.77
Cost for Child is: 33.33

那你就可以避免parent和子class同时有相同的同名方法

您可以依赖于根据实际类型调用重写方法的最佳匹配。在这种情况下,您有一个 Child 的实例。因此,当您在重写或非重写实例方法中调用重写方法时,您将看到 Child 的实现。也就是说,

Parent p = new Child();
System.out.println(p);

会给出相同的结果。

我决定在我的父 class 中放置一个带有下划线前缀的私有函数,以便能够针对该特定函数并在我的父中仍然具有通用的 public 可覆盖函数实施。

public class Parent{
    public double calculateCost(){
        return _calculateCost();
    }

    // Add this parent specific implementation
    private double _calculateCost(){
        return 77.77;
    }

    @Override
    public String toString(){
        return "Cost for Parent is: " + _calculateCost();
    }
}

public class Child extends Parent{
    @Override
    public double calculateCost(){
        return 33.33;
    }

    @Override
    public String toString(){
        return super.toString() + "\nCost for Child is: " + calculateCost();
    }

    public static void main(String[] args){
        Child child1 = new Child();
        System.out.println(child1.toString());
    }
}

我认为这是 JVM 的行为的原因,因为在 Java 中,每当我们调用一个对象的方法时,它属于 class 继承自其他 class ],JVM 检查该方法是否被 subclass 覆盖,因此尽管从 subclass 覆盖了 toString() 方法,计算 cost() 的调用解析为 subclass'版本。