在 Java 中,为啥可以从同一个包中的类外部访问受保护的成员? [复制]

Posted

技术标签:

【中文标题】在 Java 中,为啥可以从同一个包中的类外部访问受保护的成员? [复制]【英文标题】:In Java, why can a protected member be accessed from outside the class within the same package? [duplicate]在 Java 中,为什么可以从同一个包中的类外部访问受保护的成员? [复制] 【发布时间】:2015-11-23 19:53:42 【问题描述】:

在他的书中,Herbert Schildt 在第 172 页(第 3 段)中说“protected 仅在涉及继承时才适用。”。

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

以下代码有效并支持表 9-1 中的信息。

Class1.java:

package Mypack;
public class Class1

    protected pro=1;
    public Class1()
    
        System.out.println(pro);
    

Class2.java

package Mypack;
class Class2 extends Class1

    Class2()
    
        System.out.println(pro);
    

Class3.java

package Mypack;
class Class3

    Class3()
    
        Class1 class1=new Class1();
        System.out.println(class1.pro);
    

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

【问题讨论】:

Herbert Schildt 的书通常不是那么好,而且充满了不准确之处。 【参考方案1】:

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

有一种说法是这种说法是正确的,尽管我会说它非常具有误导性。再来看看the access control tutorial的访问图:

修饰符类包子类世界 公开 Y Y Y Y 受保护 Y Y Y N 无修饰符 Y Y N N 私人 Y N N N

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

但我发现它非常具有误导性,正是出于激发您的问题的原因:这似乎暗示不会有包访问权限。该语句有意义的唯一方法是,如果您已经知道 no modifier 授予包访问权限。

为了清楚起见:protected 表示一个成员可用于包中的任何类以在子类中编码。这样做可以让库拥有您只能从属于库的一部分的代码* (有点,见下文) 或有助于在库中实现某些东西的代码(例如,如果您是从库类之一子类化)。除了语言的设计方式之外,没有特别的“为什么”。

如果是这样,那么我发现在这种情况下 public 和 protected 说明符之间没有区别。

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

JLS§6.6.1:

对此进行了介绍

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

对成员或构造函数的访问发生在包含声明受保护成员或构造函数的类的包内。

访问正确,如 §6.6.2 所述。

(注意第一个项目符号)和JLS§6.6.2:

一个对象的protected 成员或构造函数可以从包外部访问,只有负责实现该对象的代码在该包中声明它。

(“负责实现该对象的代码”——例如,子类中的代码。)


* Re my “有点,见下文” on “这样做可以让库拥有您只能从属于库的一部分的代码中访问的字段和方法.. ." 这不是真的,因为除了受限制的包(例如java.lang),您可以愉快地编写自己的类,说它在库的包中,然后使用包级别的字段和方法图书馆的课程。 Java 的包概念不是字段/方法安全机制。

【讨论】:

OP 知道protected 的规则。问题是关于why a protected member is able to visible throughout the package @sᴜʀᴇsʜᴀᴛᴛᴀ:这就是我回答的问题:因为这就是规范中指定部分的定义。 感谢您的详细回答。【参考方案2】:

protected 修饰符指定该成员只能在其自己的包中访问(与 package-private 一样),此外,它的类在另一个包中的子类也可以访问。 https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html

【讨论】:

OP 知道受保护的规则。问题是关于why a protected member is able to visible throughout the package @sᴜʀᴇsʜᴀᴛᴛᴀ - 这是一个无意义的问题。【参考方案3】:

声明为protectedis visible to itself, its children, and the package it's declared in.的东西

如果Class3 位于不同的包中,例如mypack.nested,那么您将根本无法访问class1.pro

【讨论】:

【参考方案4】:

此链接上的表格显示了修饰符与 http://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html 可以访问的内容。然后根据诸如封装等良好原则需要对其他类隐藏什么需要共享等因素来选择修饰符

访问级别

修饰符类包子类世界

公开 Y Y Y Y

受保护的 Y Y Y N

没有修饰符 Y Y N N

私人 Y N N N

【讨论】:

【参考方案5】:

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

没错,在那种情况下没有区别。 考虑这段代码:

package otherpack;
public class Class4

    Class4()
    
        Class1 class1=new Class1(); // Ok, Class1 and it's constructor are public
        System.out.println(class1.pro); // Compilation error. pro is protected
    


package otherpack;
public class Class5 extends Class1

    Class5()
    
        Class1 class1=new Class1(); // Ok, Class1 and it's constructor are public
        System.out.println(class1.pro); // OK, Class5 extends Class1 and pro is protected
    

在不同包中的代码情况下public和protected是不同的。您可以使用来自不同包的公共成员,但不能使用受保护成员,除非您在派生类中这样做。

【讨论】:

以上是关于在 Java 中,为啥可以从同一个包中的类外部访问受保护的成员? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

java中的内部类

Java学习笔记--不同包的访问权限

Java 包(package)

Java 包(package)

Java 包(package)

Java 包(package)