简体   繁体   English

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

[英]The use of protected member variables from child class and abstract parent

According to our professor, the use of protected visibility should be avoided at all costs. 根据我们的教授的说法,应不惜一切代价避免使用受保护的可见性。 However, I'm a little puzzled as to why. 但是,我对为什么有些疑惑。 Say We have this for example: 说我们有这个例子:

public abstract class Animal {

    private int maxSpeed;

    public Animal() {} 

    public abstract void setMaxSpeed();

}

Where each Animal would have a max speed that would need to be defined later in the child class. 每个Animal具有最大速度的位置,稍后需要在子类中定义最大速度。 However, throwing this in: 但是,将其抛出:

public class Tutrle extends Animal {

    public Tutrle() {

    }

    @Override
    public void setMaxSpeed() {


    }

}

There is no way to be able to access the maxSpeed variable from within the overridden setMaxSpeed() method. 无法从覆盖的setMaxSpeed()方法内访问maxSpeed变量。 Although a solution would be to set maxSpeed via the constructor of the Animal class, wouldn't be better to set the maxSpeed variable to protected and have it accessible to all child sub-classes to be defined later? 尽管一种解决方案是通过Animal类的构造函数设置maxSpeed ,但将maxSpeed变量设置为protected并让以后所有定义的所有子子类都可以访问它不是更好吗?

Since the maxSpeed member is defined in the Animal class, it makes more sense for that class to have a non-abstract method that would set it : 由于maxSpeed成员是在Animal类中定义的,因此该类具有可以对其进行设置的非抽象方法就更有意义了:

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

The sub-classes (such as Turtle ) may override this method to add logic, but they should call the base class to set the value. 子类(例如Turtle )可以重写此方法以添加逻辑,但是它们应调用基类来设置值。

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

    super.setMaxSpeed(maxSpeed);
}

If setMaxSpeed() stays abstract, it would make more sense for each sub-class that implements this method to have its own maxSpeed member. 如果setMaxSpeed()保持抽象状态,则对于实现此方法的每个子类来说,拥有自己的maxSpeed成员会更有意义。

In order to access maxSpeed attribute from subclasses, you could: 为了从子类访问maxSpeed属性,您可以:

  1. Declare it as protected (your professor doesn't seem to like this very much, but I think he's lacking a suitable explanation) 将其声明为protected (您的教授似乎不太喜欢它,但是我认为他缺乏适当的解释)
  2. Declare a getMaxSpeed() method in the superclass: if knowing the max speed from outside the hierarchy is needed, declare it as public ; 在超类中声明一个getMaxSpeed()方法:如果需要从层次结构外部知道最大速度,则将其声明为public otherwise, declare it as protected , so that subclasses (specific animals, such as your Turtle ) can know what their max speed is. 否则,将其声明为protected ,以便子类(特定动物,例如Turtle )可以知道其最大速度。

I agree with @Eran in that the setMaxSpeed() method shouldn't be declared as abstract in the Animal superclass, and subclasses could call super.setMaxSpeed() from their own setMaxSpeed method if they need to do specific processing when their max speed is being set. 我同意@Eran的观点,即在Animal超类中不应将setMaxSpeed()方法声明为abstract方法,如果子类在最大速度为0时需要进行特定处理,则可以从其自己的setMaxSpeed方法中调用super.setMaxSpeed() 。被设置。

Regarding why using protected is claimed to be 'avoided at all costs', or dangerous, etc, please refer to this amazing newsletter's article . 关于为什么声称“不惜一切代价避免使用protected ”或危险的等原因,请参阅此惊人的时事通讯文章 My personal opinion is that it is wrong to make such claims, or at least, an overreaction. 我个人的观点是,做出这样的主张,或者至少是过度反应是错误的。 However, as explained in the article: 但是,如文章中所述:

We should try to only call either private or final methods from inside our constructors. 我们应该尝试仅从构造函数内部调用私有方法或最终方法。 The reason is that Java always calls the most derived method, which means we could call a method on a half-initialized object. 原因是Java总是调用最派生的方法,这意味着我们可以在半初始化对象上调用方法。

This means that if you call a protected method from within the constructor of your superclass, and that if the protected method is overriden in one of the subclasses, then the code within that method would run before the rest of the class was fully initialized, which might lead to nasty errors: 这意味着,如果您从父类的构造函数中调用protected方法,并且如果在子类之一中重写了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;
        }
    }

}

In this very simple example, this.someClass.checkIfMaxSpeedMustBeDoubled() throws a NullPointerException because this.someClass has not been yet initialized in the Animal superclass. 在这个非常简单的示例中, this.someClass.checkIfMaxSpeedMustBeDoubled()引发NullPointerException因为this.someClass尚未在Animal超类中初始化。 This kind of error is very common when using protected members, but claiming that protected should be avoided is ridiculous. 使用protected成员时,这种错误非常普遍,但是声称应该避免protected是荒谬的。 Just be careful and only call either private or final methods from within the superclass' constructor, and you'll be OK. 请小心,仅从超类的构造函数中调用private方法或final方法,您会没事的。

It is depends on requirement, If you want maxSpeed variable should be present in your all subclasses then put that variable in super class and then reuse that variable in subclass. 这取决于需求,如果希望maxSpeed变量应出现在所有子类中,则将该变量放在maxSpeed类中,然后在子类中重用该变量。 for that you have to initialize that variable through subclass constructor and change modifier to protected for that variable. 为此,您必须通过子类构造函数初始化该变量,并将该变量的修饰符更改为protected。

But its better to create variable in your subclass if those are related to your subclass only, 但是,如果子类仅与您的子类相关,则最好在子类中创建变量,

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM