【问题标题】:Java get superclass method to use subclass instance method when called by subclass子类调用时Java获取超类方法以使用子类实例方法
【发布时间】:2019-02-17 19:28:57
【问题描述】:

当子类调用时,我试图让超类方法在子类方法/字段上运行。比如

public class CoffeeMachine() {
    protected int cost = 3;

    protected int getCost() {
        return cost;
    }
}

public class FancyCoffeeMachine() extends CoffeeMachine{
    protected int cost = 6;
}

main{
    FancyCoffeeMachine expensive = new FancyCoffeeMachine();
    System.out.println(expensive.getCost());
}

我希望它打印 6,但它会打印 3。我想让它尽可能 DRY,所以我试图避免创建第二个 getCost() 方法。有没有办法做到这一点?当子类调用时,如何获得使用子类变量的超类方法?方法也会发生同样的事情:如果我有

public class makeCoffee() {
    System.out.println("Coffee cost " + this.getCost());
}

即使我在 FancyCoffeeMachine 上调用 makeCoffee,输出也会是“Coffee cost 3”。为什么是这样?我该如何解决?或者有没有更好的方法来实现这个完全规避这个错误的对象结构?

【问题讨论】:

  • 您的标题与您的问题不符。您是在询问是否使用重写的实例 字段, 而不是方法。

标签: java oop inheritance


【解决方案1】:

链接字段不像虚拟方法调用那样使用动态调度。您的字段FancyCoffeeMachine.cost 只是隐藏字段CoffeeMachine.cost

要实现您想要的(即成本较高的 FancyCoffeeMachine),您只需在 FancyCoffeeMachine 的初始化程序块或构造函数中为 CoffeeMachine.cost 字段设置一个新值。

public class CoffeeMachine {
    protected int cost = 3;

    protected int getCost() {
        return cost;
    }
}
public class FancyCoffeeMachine extends CoffeeMachine{
    {cost = 6;} // <- sets CoffeeMachine.cost
}

【讨论】:

    【解决方案2】:

    您正在从超类(CoffeeMachine)调用方法getCost,因为您的子类(FancyCoffeeMachine)中没有它。而且您的超类对子类及其字段cost 一无所知。您还应该覆盖方法 getCost 以使其像您描述的那样工作。

    【讨论】:

      【解决方案3】:

      我很确定你也必须在 FancyCoffeeMachine 上覆盖 getCost()

      public class FancyCoffeeMachine() extends CoffeeMachine{
          protected int cost = 6;
      
          protected int getCost() {
              return cost;
          }
      }
      

      但如果我想实现这个,我会做的是像这样使 CoffeeMachine 抽象

      abstract class CoffeeMachine {
          private int cost;
      
          CoffeeMachine(int cost) {
              this.cost = cost;
          }
      
          int getCost() {
              return cost;
          }
      }
      

      然后像这样在我的超类上扩展它

      class FancyCoffeeMachine extends CoffeeMachine {
          FancyCoffeeMachine(int cost) {
              super(cost);
          }
      }
      

      这样称呼它

      FancyCoffeeMachine fancyCoffeeMachine =  new FancyCoffeeMachine(6);
      System.out.println(fancyCoffeeMachine.getCost());
      

      【讨论】:

        【解决方案4】:

        您通常不会在子类中重新定义像 cost 这样的受保护字段。相反,您可以为子类提供一种在构造对象时设置成本的方法。看看这个:

        public class Scratch {
            public static class CoffeeMachine {
                protected int cost;
        
                public CoffeeMachine() {
                    this(3);
                }
        
                protected CoffeeMachine(int aCost) {
                    cost = aCost;
                }
        
                public int getCost() {
                    return cost;
                }
            }
        
            public static class FancyCoffeeMachine extends CoffeeMachine{
                public FancyCoffeeMachine() {
                    super(6);
                }
            }
        
            public static void main(String[] args) {
                System.out.printf("plain: %d\n", new CoffeeMachine().getCost());
                System.out.printf("fancy: %d\n", new FancyCoffeeMachine().getCost());
            }
        }
        

        (不用担心这两个CoffeeMachine 类被声明为静态的。这样可以将它们都定义在一个文件中。)

        基类CoffeeMachine有两个构造函数:

        1. 接受成本作为参数的受保护构造函数。
        2. 将成本设置为 3 的公共构造函数。

        子类 FancyCoffeeMachine 调用受保护的超类构造函数,成本为 6。因此,cost 变量设置为 6,getCost() 将在您运行时返回该值:

        plain: 3
        fancy: 6
        

        【讨论】:

          猜你喜欢
          • 2015-09-18
          • 2012-12-30
          • 1970-01-01
          • 1970-01-01
          • 2011-10-24
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-04-25
          相关资源
          最近更新 更多