在Java中,为什么可以在同一个包中从类外部访问受保护的成员?

PS *_*yak 16 java protected

在他的书中,Herbert Schildt在第172页(第3段)中说" 受保护仅在涉及继承时才适用".

在页228中,表9-1显示可以从同一个包中的非子类访问受保护的成员.

以下代码适用于并支持表9-1中的信息.

Class1.java:

package Mypack;
public class Class1
{
    protected pro=1;
    public Class1()
    {
        System.out.println(pro);
    }
}
Run Code Online (Sandbox Code Playgroud)

Class2.java

package Mypack;
class Class2 extends Class1
{
    Class2()
    {
        System.out.println(pro);
    }
}
Run Code Online (Sandbox Code Playgroud)

Class3.java

package Mypack;
class Class3
{
    Class3()
    {
        Class1 class1=new Class1();
        System.out.println(class1.pro);
    }
}
Run Code Online (Sandbox Code Playgroud)

可以从派生类Class2访问变量pro.但是如何从非派生类Class3通过对Class1对象的引用来访问它?它与第172页上的陈述相矛盾.如果是这样,那么在这种情况下,我发现公共和受保护的说明符之间没有区别.

T.J*_*der 19

在他的书中,Herbert Schildt在第172页(第3段)中说"受保护仅在涉及继承时才适用".

有一种观点认为这种说法是正确的,尽管我认为这是非常误导的.让我们看一下访问控制教程中的访问图表:

Modifier    Class  Package  Subclass  World
public        Y       Y        Y       Y
protected     Y       Y        Y       N
no modifier   Y       Y        N       N
private       Y       N        N       N

请注意,没有修饰符授予对成员的类和包访问权限,并且不授予对子类或世界的访问权限.protected只更改其中一项:它使成员可用于子类.所以在这个意义上,他是正确的:它只适用于涉及继承的情况; 没有继承,它与没有修饰符相同.

但是我觉得这很有误导性,因为这个问题启发了你的问题:它似乎意味着不会有包访问.声明有意义的唯一方法是,如果您已经知道没有修饰符授予包访问权限.

为清楚起见:protected表示成员可用于包中的任何类,在子类中进行编码.这样做可以使库具有只能从代码库中访问的字段和方法*(有点,见下文)或有助于在库中实现某些内容的代码(例如,如果你是从子类中进行子类化的话)其中一个图书馆类).除了那种语言的设计之外,没有特别的"为什么".

如果是这样,那么在这种情况下我发现公共和受保护的说明符之间没有区别.

在这种情况下,没有.但是,当您考虑不在同一个包中且不在包成员的派生类中的代码时,显然存在很大差异:该代码无法访问protected成员.

这在JLS§6.6.1有所涉及:

...如果声明了成员或构造函数protected,则只有在满足以下条件之一时才允许访问:

  • 从包含声明受保护成员或构造函数的类的包中发生对成员或构造函数的访问.

  • 如第6.6.2节所述,访问是正确的.

(注意第一个子弹)和JLS§6.6.2:

protected对象的成员或构造可以从它仅由代码中声明的封装,它负责该对象的执行外部访问.

("负责实现该对象的代码" - 例如,子类中的代码.)


*重新我的"有点,见下文"关于"这样做使得库可以使用只能从库中的代码访问的字段和方法......"这不是真的,因为除了受限制的包(java.lang例如),你可以愉快地编写自己的类,说它在库的包中,然后使用库级别的包级别字段和方法.Java的包概念不是字段/方法安全机制.

  • @sᴜʀᴇsʜᴀᴛᴛᴀ:这就是我回答的问题:因为在指定的部分中,它是如何在规范中定义的. (4认同)