据我们的教授说,应该不惜一切代价避免使用受保护的能见度。但是,我有点疑惑为什么。说我们有这个例子:
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
并让它可访问要在以后定义的所有子子类?
答案 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
属性,您可以:
protected
(您的教授似乎并不喜欢这样,但我认为他缺乏合适的解释)getMaxSpeed()
方法:如果需要知道层次结构外部的最大速度,请将其声明为public
;否则,将其声明为protected
,以便子类(特定动物,例如您的Turtle
)可以知道它们的最大速度是多少。我同意@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
变量,那么将该变量放在超类中,然后在子类中重用该变量。为此,你必须通过子类构造函数初始化该变量,并将修饰符更改为受保护的变量。
但如果它们只与你的子类相关,那么在子类中创建变量会更好,