Java为其类的成员提供了一种保护模式,允许子类访问它们。我在某处读到了这方面的问题。我能想到的唯一问题是程序员可能会忘记受保护的成员是API的一部分,不能随意更改。还有其他问题吗?
答案 0 :(得分:0)
在四个成员访问级别中,private和default(package-private)与封装一致,即隐藏的成员保留了实现细节的自主权。换句话说,您的API用户了解您的类实现细节的次数越少,您与该实现的关联就越少,您可以随时更改它,而不会破坏API用户所依赖的合同。< / p>
一旦你进入受保护的访问(和公共访问),那么你就会受到这种实现的约束,并且必须继续支持它,直到你的API寿命结束(或你破产)。无障碍成员倾向于将您绑定到特定的实现,即使您想要更改它,因此......许多可访问的成员与紧密封装不一致。
但更重要的是,访问也会导致风险。您的API导出的类的更多方面,恶意用户可以尝试和破解更多潜在的漏洞。
例如,受保护的访问可用于覆盖您忘记最终的类中的方法。这可能会破坏您的API,更糟糕的是,使恶意用户能够访问您不打算允许的实例数据。
答案 1 :(得分:0)
首先,我没有看到任何类的受保护成员可以被视为公共API的一部分,因为protected
字段或函数is not visible to the world。
最终,在编写API时,我们的想法是让界面或契约尽可能保持不变; 如何它可以随着每个修订而改变(虽然希望,但不是太多)。
我可能会在类中看到受保护成员的一个问题是覆盖他们的行为以从父级产生完全不同的行为,同时满足API的泛型合同(即,如果我'我期待一个数值,我得到它;如果我期待一个布尔值,我得到它。值/布尔值的正确性是可疑的,但应该测试)。< / p>
示例:假设我有一个班级Parent
和一个班级Child
。两者都实现了一个名为Teachable
的接口。这允许他们学习特定的Subject
,这是一个简单的枚举构造。 Teachable
的合同如下:
public interface Teachable {
/**
* Learn a particular subject.
* This requires that the element being learned hasn't previously been learned.
* @param thisSubject the subject to be learned
* @return whether or not the subject learned was unique.
*/
public boolean hasLearned(Subject thisSubject);
}
现在假设我们实现了Parent
和Child
类,如下所示:
public class Parent implements Teachable {
private Set<Subject> subjectsLearned = new HashSet<>();
@Override
public boolean hasLearned(final Subject thisSubject) {
return learn(thisSubject);
}
protected boolean learn(final Subject theSubject) {
return subjectsLearned.add(theSubject);
}
}
class Child extends Parent {
private Set<Subject> subjectsLearned = new HashSet<>();
@Override
public boolean hasLearned(final Subject thisSubject) {
return learn(thisSubject);
}
@Override
protected boolean learn(final Subject theSubject) {
return !subjectsLearned.add(theSubject);
}
}
我已经有效地改变了类的行为,据说它遵循我的API的行为,因为我可以覆盖它。 Child
第一次学习特定Subject
时,他们会声称他们已经知道了。只有第二次和以后的时间他们不会。