【问题标题】:Which method is called during Constructor chain execution with an overriding method在构造函数链执行期间使用覆盖方法调用哪个方法
【发布时间】:2012-02-20 22:54:51
【问题描述】:

在构造函数链执行期间使用覆盖方法调用哪个方法?鉴于以下两个类,我需要知道在创建 MountainBike 对象时将调用哪个 setGear 方法。我真正的项目与自行车无关,我试图重写一个类来改变在超类的构造函数中调用的一个方法的行为,我不确定它应该如何工作......

public class Bicycle {
    public int cadence;
    public int gear;
    public int speed;

    public Bicycle(int startCadence,
                   int startSpeed,
                   int startGear) {
        setGear(startGear);
        setCadence(startCadence);
        setSpeed(startSpeed);
    }

    public void setCadence(int newValue) {
        cadence = newValue;
    }

    public void setGear(int newValue) {
        gear = newValue;
    }

    public void applyBrake(int decrement) {
        speed -= decrement;
    }

    public void speedUp(int increment) {
        speed += increment;
    }        
}

public class MountainBike extends Bicycle {
    public int seatHeight;

    public MountainBike(int startHeight,
                        int startCadence,
                        int startSpeed,
                        int startGear) {
        super(startCadence, startSpeed, startGear);
        seatHeight = startHeight;
    }   

    public void setHeight(int newValue) {
        seatHeight = newValue;
    }

    public void setGear(int newValue) {
    if(newValue<4)
            gear = newValue;
        else{
            gear = 4;
        }

    }    
}

【问题讨论】:

  • setGear 方法根本没有被调用。也许你想在你的构造函数中调用它?
  • 我的错...它应该在 Bicycle 类的构造函数中调用...假设在 Bicycle 类构造函数中使用 setGear 来设置齿轮属性 - 修复了示例代码。 ..
  • @Steve 编写一个简单的测试并亲自看看 Java 做了什么非常容易...
  • @AndresF。是的,你是对的,但这不会帮助我理解为什么我会看到我看到的结果,如果我在我的代码中做错了什么也不会帮助我,因为我不确定它应该如何开始工作。跨度>
  • 感谢您的帮助,但我找到了一个更好的例子,其中包含我正在寻找的答案...stackoverflow.com/questions/4595512/…我想我应该在提问之前花更多时间搜索...

标签: java methods constructor chain overriding


【解决方案1】:

更一般地说,你不应该让对象引用转义它的构造函数,无论是通过将“this”作为参数传递给另一个类的方法,还是通过调用可以被覆盖的方法。

即使可以,也不应该从超类构造函数中调用被覆盖的方法。原因是超类的构造函数在子类之前运行,对象状态可能不一致。例如,子类中的最终字段尚未设置。

【讨论】:

    【解决方案2】:

    正如其他人所说,被调用的是子类的 setGear。

    但是,我想提一下,在构造函数中调用被覆盖的方法是危险的,并且不受欢迎,尤其是当这些方法依赖于子类的字段时。例如,如果 MountainBike 有一个字段,maxGear 和 setGear 引用它(而不是魔术常数 4)。问题是您的 MountainBike 构造函数看起来像:

    public MountainBike(args...) {
      super(args);  // must come first!!!
      maxGear = 4;
    }
    

    Bicycle 构造函数调用 setGear() 时,会调用 MountainBike 的 setGear,但 maxGear 尚未设置 - 它将为 0。

    【讨论】:

    • +1 指出“在构造函数中调用被覆盖的方法是危险的并且不赞成
    【解决方案3】:

    如果你实例化重写类,那么它的重写方法将被执行。

    Bicycle bike;
    
    bike = new Bicycle(1,2,3);
    bike.setGear(8);//Bicycle's setGear is run
    
    bike = new MountainBike(1,2,3,4);
    bike.setGear(8);//MountainBike's setGear is run
    

    -- 编辑:反映 OP 编辑​​的问题(setGear 现在从 Bicycle 的构造函数中调用)--

    Bicycle b=new MountainBike(1,2,3,4);
    

    假设您实例化了 MountainBikeMountainBikesetGear 将被执行。

    【讨论】:

      【解决方案4】:

      这里有一些很好的答案,但我想提一下,您应该考虑改用合成。我见过许多项目,其中继承用于可以以更好的方式通过组合完成的功能。在项目的后期阶段,这可能会导致严重的问题和代码异味。

      参见“优先组合优于继承”:Effective Java: Item 16

      【讨论】:

        【解决方案5】:

        是的,重写基类方法以在派生类中创建和容纳新功能是定义子类型 - 多态特性的原因。

        class A{methodA...}
        class B extends A{methodA...}
        A a=new B;
        a.methodA(); <<<< this should call B's methodA
        

        【讨论】:

          【解决方案6】:

          如果你调用它,子类的方法就会执行。但是,它目前没有被调用。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-03-01
            • 2014-05-22
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2018-04-21
            • 2014-01-18
            相关资源
            最近更新 更多