有关在Java中访问受保护成员的问题已经被提出并且已经回答了很多次,例如: Java: protected access across packages
但我无法理解为什么以这种方式实现,请参阅“Java Programming Language”(第4版)中的解释:
“限制背后的原因是:每个子类继承超类的契约并以某种方式扩展该契约。假设一个子类作为其扩展契约的一部分,对受保护成员的值施加约束。超类。如果一个不同的子类可以访问第一个子类的对象的受保护成员,那么它可以以破坏第一个子类的合同的方式操纵它们,这不应该是允许的。“
好的,这很清楚,但请考虑这种继承结构(从某些代码中提取):
package package1;
public class A {
protected int x;
}
package package2;
public class B extends A {
public static void main(String[] args)
C subclass = new C();
subclass.x = 7; // here any constraints can be broken - ??
}
}
class C extends B {
// class which places constraints on the value of protected member x
...
}
这里subclass.x = 7是一个有效的陈述,仍然可以打破C的合约。 我错过了什么?
编辑(补充):也许我不应该在这种情况下应用引用的逻辑?如果我们只处理一个包,则根本不存在任何限制。因此,直接继承链可能会以简化的方式处理,这意味着超类必须知道它在做什么......
答案 0 :(得分:2)
最终所有关于遵循合同的内容,如您公布的报价中所述。如果你真的担心有人不会阅读合同,那么所有这些都有一个防御性的编程解决方案,它引入了修改验证。
我的意思是你发布的代码可能会违约;然而,这不可能:
public class A {
private int x;
protected final void setX(int x) throws IllegalArgumentException {
if (x < 0)
throw new IllegalArgumentException("x cannot be negative");
subValidateX(x);
this.x = x;
}
/**
* Subclasses that wish to provide extra validation should override this method
*/
protected void subValidateX(int x) {
// Intentional no-op
}
}
在这里,我做了三件大事:
x
设为私有,因此只能在A
内分配(当然不包括反射等内容),final
,它阻止了子类覆盖它并删除了我的验证,protected
方法,可以被子类覆盖以提供额外的验证,以确保子类可以缩小 x
上的要求,但不是扩展它们包含负整数等内容,因为我的验证已经检查过。有很多很好的资源可以用来设计Java中的继承,特别是在涉及超级防御性保护合同API编程时,就像上面的例子一样。我建议您在自己喜欢的搜索引擎上查找它们。
但最终,编写子类的开发人员需要负责阅读文档,尤其是当您进入接口实现时。
答案 1 :(得分:0)
继承的类与其父级隐式地是朋友。因此,只要C从B继承,B对C的x属性有远见就是正常的。
答案 2 :(得分:0)
自C extends B
起,
C c = new C();
c.x = 1;
对于您的问题,与
完全相同B b = new C();
b.x = 1;
Java编译器不考虑上述代码中b
和c
引用的对象的运行时类型;它看到的只是声明的类型,分别是B
和C
。现在,因为我的第二个例子显然必须工作(类B
中的代码正在访问它自己的属性,毕竟),第一个例子也必须工作;否则就意味着Java允许你在更具体的类型上做 less ,这是一个悖论。