2013-05-12 77 views
0

Java为其类的成员提供了保护模式,允许子类访问它们。我在某处读到这个问题。我能想到的唯一问题是程序员可能会忘记受保护的成员是API的一部分,不能任意改变。还有其他问题吗?受保护的类成员访问有哪些问题?

回答

0

在四种成员访问级别中,私有和默认(包私有)与封装协调一致,即隐藏的成员保留了实现细节的自主性。换句话说,您的API用户对您的类实现细节的了解越少,您与该实现绑定的越少,并且随时可以更改它,而不会违反API用户所依赖的合同。

一旦您进入受保护的访问(以及公共访问),您就会被绑定到该实现,并且必须继续支持它,直到您的API生命结束(或您退出业务)。可访问的成员往往会将您与特定的实现联系起来,即使您想要更改它,所以......许多可访问的成员与严格的封装不一致。

但是,不仅如此,访问还会出口风险。您的API导出的类的更多方面,那么恶意用户可以尝试和破解的潜在漏洞更多。

例如,可以使用受保护的访问来覆盖您忘记进行最终操作的类中的方法。这可能会破坏您的API,更糟糕的是,会使恶意用户访问您不打算允许的实例数据。

+0

用户看不到代码,只有程序员。什么是阻止程序员在代码的任何地方添加恶意的意图? – shawnhcorey 2013-05-13 13:37:03

0

首先,由于protected字段或函数is not visible to the world,我没有看到任何类的受保护成员可以被视为公共API的一部分。

最终,在编写API时,想法是让接口或合约尽可能不变; 如何它的完成可以改变每个修订(尽管希望,不要太多)。

一个问题我可能与类保护成员看到会被重写他们的行为从父产生根本不同的行为,同时满足通用合同的API(也就是说,如果我期待的数值值,我把它取回来;如果我期待一个布尔值,我将它取回。值/布尔值的正确性可疑,但应该测试)。

例如:假设我有一个类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); 
} 

现在假设我们有实现ParentChild类如下:

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,他们会声称他们已经知道它。只有第二次和以后的时间他们不会。

+0

根据Joshua Bloch的说法,封装是一种理想和珍贵的东西。他还提出了令人信服的论点,即继承破坏了封装,并且进一步说,继承应该只保留给那些具有确定的“是”关系的类设计。我只是以最具体的含义来指代你的例子:因为“孩子是父母”不是真的,在这种情况下使用受保护的方法和继承可能会导致脆弱的设计。 – scottb 2013-05-12 19:04:29

+0

我不反对。事实上,这可能是一种反模式;人们应该真的为这种“是一种”关系保留继承权,就你而言。但是,很可能情况是某个API的某个地方确实有可以被覆盖的受保护方法,从而导致不一致/无效的合同。 – Makoto 2013-05-12 19:40:20

+0

首先,受保护的成员不是公共API的一部分;它是受保护的API的一部分。接下来,封装可能是可取的,但许多API只是在他们工作的希望中一起抛出。要创建一个良好的API,你必须问每个元素两个问题:这是否足够,这是必要的?第一个问题确保API传输足够的信息来做有用的工作,其次确保API是最小的必需。 – shawnhcorey 2013-05-12 21:38:28