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

Java 使用子类和抽象父类中受保护的成员变量,java,polymorphism,Java,Polymorphism,根据我们的教授,应该不惜一切代价避免使用受保护的可见性。然而,我有点不解为什么。比如说我们有: public abstract class Animal { private int maxSpeed; public Animal() {} public abstract void setMaxSpeed(); } 其中,每个动物都有一个最大速度,该速度需要在以后的子类中定义。然而,把这个放进去: public class Tutrle extends Anim

根据我们的教授,应该不惜一切代价避免使用受保护的可见性。然而,我有点不解为什么。比如说我们有:

public abstract class Animal {

    private int maxSpeed;

    public Animal() {} 

    public abstract void setMaxSpeed();

}
其中,每个
动物
都有一个最大速度,该速度需要在以后的子类中定义。然而,把这个放进去:

public class Tutrle extends Animal {

    public Tutrle() {

    }

    @Override
    public void setMaxSpeed() {


    }

}

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

这取决于需求,如果您希望
maxSpeed
变量应该出现在您的所有子类中,那么将该变量放在超类中,然后在子类中重用该变量。为此,您必须通过子类构造函数初始化该变量,并将该变量的修饰符更改为protected


但如果子类中的变量只与子类相关,则最好在子类中创建变量,

因为
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
成员将更有意义。

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

  • 将它声明为受保护的(你的教授似乎不太喜欢这个,但我认为他缺乏合适的解释)
  • 在超类中声明一个
    getMaxSpeed()
    方法:如果需要从层次结构外部知道最大速度,则将其声明为
    public
    ;否则,将其声明为
    受保护
    ,以便子类(特定动物,如您的
    海龟
    )可以知道它们的最大速度
  • 我同意@Eran的观点,即
    setMaxSpeed()
    方法不应在
    Animal
    超类中声明为
    abstract
    ,如果子类在设置其最大速度时需要进行特定处理,则可以从自己的
    setMaxSpeed()方法调用
    super.setMaxSpeed()

    关于为什么声称使用受保护的
    是“不惜一切代价避免的”或危险的,请参阅此。我个人的观点是,提出这样的主张是错误的,或者至少是反应过度。然而,正如文章中所解释的:

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

    这意味着,如果从超类的构造函数中调用
    受保护的
    方法,并且如果在其中一个子类中重写了
    受保护的
    方法,则该方法中的代码将在类的其余部分完全初始化之前运行,这可能会导致严重错误:

    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.CheckIfMaxSpeedMustedoubled()
    抛出一个
    NullPointerException
    ,因为
    this.someClass
    尚未在
    Animal
    超类中初始化。这种错误在使用
    受保护的
    成员时非常常见,但声称应避免
    受保护的
    是荒谬的。只要小心,只从超类的构造函数中调用
    private
    final
    方法,就可以了。

    在这种特殊情况下,我会将
    maxSpeed
    字段移到一个具体的类中。我不同意,@ILoveCoding
    maxSpeed
    应该是每个动物定义的一部分,这就是为什么位于
    abstract
    类中的原因。然而,我会为它的价值引入一个
    protected
    getter。声称“应该不惜一切代价避免使用protectedvisibility”有点过分。你的教授在这件事上是原教旨主义者。然而,
    protected
    确实会导致一些OO设计错误。