为什么受保护的实例成员在不同包中的子类内不可见,但受保护的类成员是?

мај*_*мех 6 java

package one;

public class A {
    protected int first;
    protected static int second;
}
Run Code Online (Sandbox Code Playgroud)

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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

Vin*_*igh 6

JLS 6.6.2:

受保护的成员或对象的构造函数可以从包外部访问,只能通过负责实现该对象的代码来声明它.

6.6.2.1开始:

设C是声明受保护成员的类.仅允许在C的子类S的主体内访问.

this.first = 5;因为B是的实现者而工作A.

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);
    }
}
Run Code Online (Sandbox Code Playgroud)

和threePoint包声明:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

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


我建议检查为什么我们不应该protected static在Java中使用.

语义protected是针对实例成员的 - protected static与目的相矛盾protected,这可能是为什么它不以同样的方式受到限制.