为啥受保护的实例成员在不同包的子类中不可见,但受保护的类成员是? [复制]

Posted

技术标签:

【中文标题】为啥受保护的实例成员在不同包的子类中不可见,但受保护的类成员是? [复制]【英文标题】:Why are protected instance members not visible inside a subclass within a different package, but protected class members are? [duplicate]为什么受保护的实例成员在不同包的子类中不可见,但受保护的类成员是? [复制] 【发布时间】:2018-02-11 11:31:00 【问题描述】:
package one;

public class A 
    protected int first;
    protected static int second;

package two;

import one.A;

public class B extends A 
    public void someMethod() 
        this.first = 5; //works as expected
        B.second = 6; //works
        A a = new A();
        // a.first = 7; does not compile

        //works just fine, but why?
        a.second = 8; 
        A.second = 9;
    

为什么对静态字段应用不同的限制,其背后的想法是什么?

【问题讨论】:

【参考方案1】:

来自JLS 6.6.2:

对象的受保护成员或构造函数可以从包的外部访问,在该包中只能由负责实现那个对象。

来自6.6.2.1:

令 C 为声明受保护成员的类。只允许在 C 的子类 S 的主体内访问。

this.first = 5; 有效,因为BA 的实现者。

A.second 有效,因为此限制仅针对对象的成员定义。 B.second 也是如此。

至于为什么这样指定,你得问问定义规范的人——我们只能做出假设。 6.6.2.1 甚至有一个例子表达了类似的问题

考虑这个例子,其中 points 包声明:

package points;
public class Point 
    protected int x, y;
    void warp(threePoint.Point3d a) 
        if (a.z > 0)  // compile-time error: cannot access a.z
            a.delta(this);
    

并且三点包声明:

package threePoint;
import points.Point;
public class Point3d extends Point 
    protected int z;
    public void delta(Point p) 
        p.x += this.x;  // compile-time error: cannot access p.x
        p.y += this.y;  // compile-time error: cannot access p.y
    
    public void delta3d(Point3d q) 
        q.x += this.x;
        q.y += this.y;
        q.z += this.z;
    

这里的方法 delta 出现编译时错误:它无法访问其参数 p 的受保护成员 x 和 y,因为 而 Point3d(其中出现对字段 x 和 y 的引用的类)是Point 的子类(在其中声明 x 和 y 的类),它不参与 Point 的实现(参数 p 的类型)。方法 delta3d 可以访问其参数 q 的受保护成员,因为类 Point3d 是 Point 的子类,并且涉及到 Point3d 的实现。


我建议查看Why we should not use protected static in Java。

protected 的语义是针对实例成员的 - protected staticprotected 的目的相矛盾,这可能是它没有以相同方式限制的原因。

【讨论】:

嗨,我还没有得到答案,受保护的静态变量如何访问?在这种情况下,a.second = 8;可访问 @nagendra547 限制只是实例成员的集合;类成员不受这种方式的限制。该规范仅对实例成员有此要求。 好吧,你不能访问类成员,例如 a.second,如果 B 没有扩展 A。 @nagendra547 这在 6.6.2.1 中涵盖:“令 C 为声明受保护成员的类。仅允许在 C 的子类 S 的主体内访问。 i>" - 由于BA 的子类,因此可以访问受保护的成员。 6.6.2 强制实例成员的限制。两种不同的合同。仅当BA 在同一个包中时,B 仍然可以访问A.second 而无需扩展。 我不得不说,这个“参与执行”业务的措辞相当糟糕。 'Member of' 会更好,更简单。

以上是关于为啥受保护的实例成员在不同包的子类中不可见,但受保护的类成员是? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

为啥 Java 允许增加子类中受保护方法的可见性?

为啥受保护的修饰符在 Java 子类中的行为不同?

超类中的受保护方法在不同包中的子类中是不是可见? [复制]

为啥同一类而不是同一对象可以访问受保护和私有属性?

Java中的间接子类无法访问的超类中的受保护成员

java中不同包的受保护成员访问-好奇心[重复]