为什么在Java中实现对受保护成员的访问?

时间:2013-06-23 04:25:29

标签: java subclass implementation protected

有关在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的合约。 我错过了什么?

编辑(补充):也许我不应该在这种情况下应用引用的逻辑?如果我们只处理一个包,则根本不存在任何限制。因此,直接继承链可能会以简化的方式处理,这意味着超类必须知道它在做什么......

3 个答案:

答案 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
    }
}

在这里,我做了三件大事:

  1. 我将x设为私有,因此只能在A内分配(当然不包括反射等内容),
  2. 我创建了setter final,它阻止了子类覆盖它并删除了我的验证,
  3. 我创建了一个protected方法,可以被子类覆盖以提供额外的验证,以确保子类可以缩小 x上的要求,但不是扩展它们包含负整数等内容,因为我的验证已经检查过。
  4. 有很多很好的资源可以用来设计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编译器不考虑上述代码中bc引用的对象的运行时类型;它看到的只是声明的类型,分别是BC。现在,因为我的第二个例子显然必须工作(类B中的代码正在访问它自己的属性,毕竟),第一个例子也必须工作;否则就意味着Java允许你在更具体的类型上做 less ,这是一个悖论。