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

2022-09-03 00:51:39

赫伯特·希尔德特(Herbert Schildt)在他的书中在第172页(第3段)中说,“受保护的只适用于涉及继承的情况。

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

以下代码工作正常,并支持表 9-1 中的信息。

第1类.java:

package Mypack;
public class Class1
{
    protected pro=1;
    public Class1()
    {
        System.out.println(pro);
    }
}

类别2.java

package Mypack;
class Class2 extends Class1
{
    Class2()
    {
        System.out.println(pro);
    }
}

类别3.java

package Mypack;
class Class3
{
    Class3()
    {
        Class1 class1=new Class1();
        System.out.println(class1.pro);
    }
}

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


答案 1

赫伯特·希尔德特(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的包概念不是字段/方法安全机制。java.lang


答案 2

受保护的修饰符指定只能在其自己的包中访问成员(与包专用一样),此外,还可以由另一个包中其类的子类访问。https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html


推荐