从子类和抽象父级使用受保护的成员变量

时间:2015-01-29 13:38:04

标签: java polymorphism

据我们的教授说,应该不惜一切代价避免使用受保护的能见度。但是,我有点疑惑为什么。说我们有这个例子:

public abstract class Animal {

    private int maxSpeed;

    public Animal() {} 

    public abstract void setMaxSpeed();

}

每个Animal的最大速度都需要在子类中稍后定义。然而,把它扔进:

public class Tutrle extends Animal {

    public Tutrle() {

    }

    @Override
    public void setMaxSpeed() {


    }

}

无法从重写的maxSpeed方法中访问setMaxSpeed()变量。虽然解决方案是通过maxSpeed类的构造函数设置Animal,但最好将maxSpeed变量设置为protected并让它可访问要在以后定义的所有子子类?

3 个答案:

答案 0 :(得分:2)

由于在maxSpeed类中定义了Animal成员,因此该类有一个非抽象方法可以设置它更有意义:

public void setMaxSpeed(int maxSpeed)
{
    this.maxSpeed = maxSpeed;
}

子类(例如Turtle)可以覆盖此方法以添加逻辑,但是它们应该调用基类来设置值。

@Override
public void setMaxSpeed(int maxSpeed)
{
    if (maxSpeed > 5)
        throw new SomeException();

    super.setMaxSpeed(maxSpeed);
}

如果setMaxSpeed()保持抽象,那么实现此方法的每个子类都有自己的maxSpeed成员更有意义。

答案 1 :(得分:1)

为了从子类访问maxSpeed属性,您可以:

  1. 将其声明为protected(您的教授似乎并不喜欢这样,但我认为他缺乏合适的解释)
  2. 在超类中声明getMaxSpeed()方法:如果需要知道层次结构外部的最大速度,请将其声明为public;否则,将其声明为protected,以便子类(特定动物,例如您的Turtle)可以知道它们的最大速度是多少。
  3. 我同意@Eran的意见,setMaxSpeed()方法不应在abstract超类中声明为Animal,而子类可以从其super.setMaxSpeed()调用setMaxSpeed如果他们需要在设置最大速度时进行特定处理,则使用自己的protected方法。

    关于为什么使用protected声称不惜一切代价避免使用,或危险等,请参阅此amazing newsletter's article。我个人认为,提出这样的主张是错误的,或者至少是过度反应。但是,正如文章中所解释的那样:

      

    我们应该尝试只从构造函数中调用private或final方法。原因是Java总是调用派生最多的方法,这意味着我们可以在半初始化对象上调用方法。

    这意味着如果从超类的构造函数中调用protected方法,并且如果在其中一个子类中覆盖class Animal { protected int maxSpeed; protected SomeClass someClass; protected Animal(int maxSpeed, SomeClass someClass) { this.setMaxSpeed(maxSpeed); // call to subclass method this.someClass = someClass; } public abstract void setMaxSpeed(int maxSpeed); // could also be protected } class Turtle extends Animal { @Override public void setMaxSpeed(int maxSpeed) { if (this.someClass.checkIfMaxSpeedMustBeDoubled()) { // throws NPE this.maxSpeed = maxSpeed * 2; } else { this.maxSpeed = maxSpeed; } } } 方法,则该方法中的代码将运行之前该类的其余部分已完全初始化,这可能会导致令人讨厌的错误:

    this.someClass.checkIfMaxSpeedMustBeDoubled()

    在这个非常简单的示例中,NullPointerException会引发this.someClass因为Animal尚未在protected超类中初始化。使用protected成员时,这种错误很常见,但声称应该避免使用private是荒谬的。请注意,只能在超类中调用final或{{1}}方法。构造函数,你没事。

答案 2 :(得分:0)

这取决于要求,如果你想在你的所有子类中都存在maxSpeed变量,那么将该变量放在超类中,然后在子类中重用该变量。为此,你必须通过子类构造函数初始化该变量,并将修饰符更改为受保护的变量。

但如果它们只与你的子类相关,那么在子类中创建变量会更好,