【问题标题】: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 的书通常不是那么好,而且充满了不准确之处。

标签: java protected


【解决方案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是不同的。您可以使用来自不同包的公共成员,但不能使用受保护成员,除非您在派生类中这样做。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-09-22
        • 2018-02-11
        • 1970-01-01
        • 2011-12-25
        • 2011-01-06
        • 2015-03-05
        • 1970-01-01
        • 2011-07-30
        相关资源
        最近更新 更多