【问题标题】:Why can a class not be defined as protected?为什么不能将类定义为受保护的?
【发布时间】:2011-04-21 15:19:03
【问题描述】:

为什么我们不能将一个类定义为protected

我知道我们不能,但为什么呢?应该有一些具体的原因。

【问题讨论】:

标签: java class protected


【解决方案1】:

因为没有意义。

受保护的类成员(方法或变量)就像包私有(默认可见性)一样,除了它也可以从子类访问。
由于 Java 中没有“子包”或“包继承”这样的概念,因此声明类受保护或包私有将是一回事。

不过,您可以将嵌套类和内部类声明为受保护或私有。

【讨论】:

  • > 由于 Java 中没有“子包”或“包继承”这样的概念,因此声明类受保护或包私有将是一回事。为什么受保护的类与包私有具有相同的可见性?不是和公众一样吗?谢谢。
  • @Nikita Ryback 你能解释一下什么是 subPackage 或 package-inheritance 吗?我还不清楚为什么在顶级类中使用 protected。如果你用例子来解释会很棒。
  • 当您将类成员声明为受保护时,它的可见性是同一包中的类(称为包访问)和子类。如果您尝试从其他包中的外部类访问此受保护的方法成员是不可见的。
  • @kelgwiin 我相信你不应该混合类的访问修饰符和成员的访问修饰符。因为两者不同。虽然类允许将自身修改为公共或默认值,但成员可以修改为公共、私有、受保护和默认值。
  • “因为它没有意义”——这是一个相当大胆的声明。它没有在 Java 中定义,但存在类似的东西确实;例如Kotlin 中的 open 允许在当前包之外进行子类化(可以想象 Java 中的 protected 会阻止这种情况,默认设置相反)。
【解决方案2】:

如您所知,default 用于包级别访问,protected 用于包级别和非包类,但它扩展了此类(这里要注意的是,只有当类可见时,您才能扩展该类!)。 让我们这样说:

  • 受保护的顶级类对其包中的类可见。
  • 现在让它在包(子类)之外可见有点令人困惑和棘手。应该允许哪些类继承我们的受保护类?
  • 如果所有类都允许子类化,那么它将类似于公共访问说明符。
  • 如果没有,则类似于默认值。

由于无法限制此类仅由少数类子类化(我们不能限制类仅由包中/包外所有可用类中的少数类继承),因此没有使用顶级类的受保护访问说明符。因此是不允许的。

【讨论】:

  • "现在让一个受保护的类在包外可见(子类)有点混乱和棘手。应该允许哪些类继承我们的受保护类?如果所有类都允许子类化,那么它将类似于公共访问说明符。”真的帮助我理解了为什么受保护的类没有意义的问题:)
【解决方案3】:
public class A
{
    protected class B
    {
    }
}

【讨论】:

    【解决方案4】:

    定义一个受保护的字段使得该字段可以在包内部以及包外部通过继承访问(仅在子类内部)。

    因此,如果我们被允许对一个类进行保护,那么我们可以很容易地在包内访问它,但是要在包外访问该类,我们首先需要扩展定义该类的实体,即其包。

    由于包不能扩展(可以导入),定义一个受保护的类将再次使其成为包私有,这类似于我们已经可以将其定义为默认值。 因此,将类定义为私有没有任何好处,它只会使事情变得模棱两可。

    更多信息请阅读Why an outer Java class can’t be private or protected

    【讨论】:

    【解决方案5】:

    @Nikita Rybak answer有优点,但缺乏细节,我自己不深思就不能简单地得到想法,以下是我的想法,现在我应该完全明白原因了。

    四个访问修饰符,假设第 1 级是公共的,第 4 级是私有的(依次基于此table)。首先我们应该知道为什么类不能在顶层定义为私有的。

    因此,如果“私有类 foo”(定义的私有成员,即类本身是成员)允许,那么外部(包含该成员)是什么? 文件范围?不,文件外部是没有意义的,因为即使单个文件中的多个类也会被编译成单独的类文件。 所以外层是包。但是第三级默认访问修饰符已经意味着“包私有”。所以第 4 级私有访问修饰符将不会被使用/允许。

    但是嵌套私有类是允许的,因为直接外部是类,而不是包,e.g.

    class PrivateNestedMain {
        private static class Inner {
            public static void main(String[] args) {
                System.out.println("Hello from Inner!");
            }
        }
    }
    

    现在如果“受保护的类 foo”允许呢? protected 主要特征是子类,因此外部(包)应该(由于范围最大,但仍然是可选的)提供子类的样式,即子包,或package A extends package B,但我们不知道这样的事情。所以 protected 不能在外部是包的顶层使用全部潜力(主要范围是子类范围)(即没有这样的子包),但 protected 可以在外部的嵌套类中使用全部潜力是类(即可以是子类)

    class ProtectedNestedMain {
        protected static class Inner {
            public static void main(String[] args) {
                System.out.println("Hello from Inner!");
            }
        }
    }
    

    请注意,上面所说的“不能充分发挥潜力”是因为它不能达到子类范围仅仅因为没有外部子类,这意味着实际上可以允许保护如果外部不能子类化,避免重复包私有的工作只是一个选择问题,见下文。

    我的困惑主要是https://docs.oracle.com/javase/tutorial/java/javaOO/accesscontrol.html的著名表造成的:

    如果允许 1 级(公共)和 3 级(包私有),那么中间的 2 级(受保护)到底是如何不允许的?

    public 支持子类所以容易误导。正确的读法是

    如果外部具有子类功能,则公共支持子类。

    同样的误导适用于包私有,包私有不支持子类(单元格中的N)并不意味着子类概念适用于外部。

    这意味着如果子类功能在外部不可用,我们应该忽略 Subclass 列:

    正如我们现在所看到的,protected 和 package-private 现在是同一级别(Y-Y-N),不再混淆为什么不允许中间级别。总的来说,Java 只选择包私有而不是受保护以避免混淆(这只是一个选择问题,但受保护的主要特征是子类,因此包私有更优越),和result,顶层只允许2个访问修饰符:

    在顶层——公共或包私有(无显式修饰符)。

    【讨论】:

      【解决方案6】:

      Protected 与 public 不同。受保护的具有包级别的访问权限,并且只能通过继承在包之外访问。如果一个类说包外的 A 从其他包继承一个类(通过使用 INHERITANCE 使用受保护的方法),它可以访问这个类 B 的方法具有受保护的方法,但从该类派生的子类,即 A 无法访问受保护的方法..相反的情况发生在 public..

      例子:

      package 2;
      class B
      {
      protected void method1()
      {
      }
      }
      package 1;
      import 2.B;
      class A extends B
      {
      //can access protected method
      }
      class C extends A
      {
      //can't access the protected method
      }
      

      【讨论】:

        【解决方案7】:

        如果一个外部类是由protected声明的,我想你希望这个类只能从同一个包及其子类访问,但不同的包。但是,不可能为受保护的类创建子类,因为当您编写“狗类扩展动物”时,因为受保护的“动物”只能被其子类访问,显然“狗”不是“动物”子类.

        因此受保护的外部类与(默认)外部类相同!

        【讨论】:

          【解决方案8】:

          “受保护”的行为=“默认”的行为+“在任何包的任何子类中使用它”。

          无论如何,我们都有默认的类访问修饰符,我们可以从受保护的访问修饰符中获得的唯一好处是:- 通过子类化在任何包中使用它。但是对于子类,父“受保护”类的可见性将是私有的。所以无法访问。基本上,如果您有一个受保护的顶级类,则没有外部类可以通过继承它来获得访问权限。所以对顶级类进行保护是没有意义的。

          【讨论】:

            【解决方案9】:

            受保护:仅对包级别可见*。

            类是定义的受保护的 --->它不能从外部包扩展(不可见)。

            如果它不能扩展,那么保持它为protected是没有意义的,因为那样它将成为允许的默认访问。

            同样适用于私有定义的类。

            注意:嵌套或内部类可以定义为protectedprivate

            * :探索 protected 关键字,对于这个答案,我做得很简洁。

            【讨论】:

              【解决方案10】:

              @Akash5288 的回答对我来说毫无意义:

              如果所有类都被允许子类化,那么它将类似于公共访问说明符。

              由于无法限制此类仅由少数类继承(我们不能限制类仅由包中/包外所有可用类中的少数类继承),因此没有使用顶级类的受保护访问说明符。因此是不允许的。

              然后您可以将相同的逻辑应用于受保护的方法和变量,它们也“类似于公共”。包外的所有类都可以扩展我们的公共类并使用其受保护的方法。为什么将方法和变量限制为扩展类可以,但限制整个类不行? “与公众相似”不是“与公众相同”。我的解释是允许受保护的类是完全可以的,因为允许受保护的方法也可以。

              “你不能扩展你不能访问/看到的类”这个答案更合乎逻辑。

              【讨论】:

                【解决方案11】:

                这个问题的意义在于,JVM 是用 C(Sun JVM)和 C++(oracle JVM)编写的,所以在编译期间,我们将从我们的 java 文件中创建 .class 文件,如果我们声明一个类使用 Protected 关键字,则 JVM 将无法访问它。

                JVM 不会访问受保护类的答案是,因为受保护的字段可以在同一个包中访问,或者只能通过继承访问不同的包,并且 JVM 的编写方式不是为了使其继承将类。 希望这能满足这个问题:)

                同样,顶级类不能是私有的。解释如下:

                如果我们定义一个私有类会发生什么,该类只能在定义它的实体中访问,在我们的例子中是它的包?

                因此,定义对类的私有访问将使它可以在默认关键字已经为我们做的同一个包中访问,因此定义一个私有类没有任何好处,它只会使事情变得模棱两可。

                【讨论】:

                  【解决方案12】:

                  protected 表示该成员可以被同一个包中的任何类访问 和子类,即使它们在另一个包中。

                  例子:

                  package a;
                  class parent{
                   protected void p();
                  }
                  package b;
                  import a.p;
                  class child extends parent{
                    //you can access method which is protected in the parent in the child 
                  }
                  class another extends child {
                   //here you can not access the protected method 
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 2014-05-16
                    • 1970-01-01
                    • 2013-03-05
                    • 2013-10-01
                    • 2013-01-23
                    • 2011-10-06
                    • 1970-01-01
                    相关资源
                    最近更新 更多