Dimitri
Dimitri

Reputation: 1966

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. 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. 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?

Upvotes: 2

Views: 2349

Answers (3)

fps
fps

Reputation: 34460

In order to access maxSpeed attribute from subclasses, you could:

  1. Declare it as protected (your professor doesn't seem to like this very much, but I think he's lacking a suitable explanation)
  2. Declare a getMaxSpeed() method in the superclass: if knowing the max speed from outside the hierarchy is needed, declare it as public; otherwise, declare it as protected, so that subclasses (specific animals, such as your Turtle) can know what their max speed is.

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.

Regarding why using protected is claimed to be 'avoided at all costs', or dangerous, etc, please refer to this amazing newsletter's article. 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.

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:

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 kind of error is very common when using protected members, but claiming that protected should be avoided is ridiculous. Just be careful and only call either private or final methods from within the superclass' constructor, and you'll be OK.

Upvotes: 1

Eran
Eran

Reputation: 393821

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 :

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.

@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.

Upvotes: 2

atish shimpi
atish shimpi

Reputation: 5023

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. for that you have to initialize that variable through subclass constructor and change modifier to protected for that variable.

But its better to create variable in your subclass if those are related to your subclass only,

Upvotes: 0

Related Questions