Java中受保护和包私有访问修饰符之间的区别?

Java中受保护和包私有访问修饰符之间的区别?,java,package,protected,access-modifiers,Java,Package,Protected,Access Modifiers,我已经看过关于受保护和包私有修饰符之间差异的各种文章。我发现这两篇文章之间有一点是矛盾的 在这一点上,公认的答案是 protected修饰符指定成员只能在其自己的包内访问(与包private一样),此外,还可以由另一个包中其类的子类访问 在这一点上,公认的答案是 要满足受保护级别访问,必须满足两个条件: 这些类必须在同一个包中 必须存在继承关系 他们不矛盾吗?根据我对其他文章的理解,第一篇文章给出了正确的答案,protected==包private+其他包中的subclass 如果这

我已经看过关于受保护和包私有修饰符之间差异的各种文章。我发现这两篇文章之间有一点是矛盾的

  • 在这一点上,公认的答案是

    protected修饰符指定成员只能在其自己的包内访问(与包private一样),此外,还可以由另一个包中其类的子类访问

  • 在这一点上,公认的答案是

    要满足受保护级别访问,必须满足两个条件:

    • 这些类必须在同一个包中
    • 必须存在继承关系
  • 他们不矛盾吗?根据我对其他文章的理解,第一篇文章给出了正确的答案,protected==包private+其他包中的subclass

    如果这句话是正确的,那么为什么这段代码在第17行的子类Cat上出现以下错误消息时失败

    The method testInstanceMethod() from the type Animal is not visible 
    
    我的超级和子类代码如下

    package inheritance;
    
    public class Animal {
    
        public static void testClassMethod() {
            System.out.println("The class" + " method in Animal.");
        }
        protected void testInstanceMethod() {
            System.out.println("The instance " + " method in Animal.");
        }
    }
    
    package testpackage;
    
    import inheritance.Animal;
    
    public class Cat extends Animal{
            public static void testClassMethod() {
                System.out.println("The class method" + " in Cat.");
            }
            public void testInstanceMethod() {
                System.out.println("The instance method" + " in Cat.");
            }
    
            public static void main(String[] args) {
                Cat myCat = new Cat();
                Animal myAnimal = myCat;
                myAnimal.testClassMethod();
                myAnimal.testInstanceMethod();
            }
        }
    

    请澄清上述代码失败的原因。这将非常有用。谢谢

    第一个答案基本正确-
    受保护的
    成员可以通过

    • 来自同一包的类
    • 来自其他包的声明类的子类
    然而,有一个小技巧:

    6.6.2受保护访问的详细信息

    对象的受保护成员或构造函数可以从包的外部访问,在包中它只能由负责该对象实现的代码声明

    这意味着来自其他包的子类不能访问其超类的任意实例的
    受保护的
    成员,它们只能在自己类型的实例上访问它们(其中type是表达式的编译时类型,因为它是编译时检查)

    例如(假设此代码位于
    Cat
    ):

    这是有意义的,因为通过
    Cat
    访问
    protected
    狗的
    成员可能会破坏
    Dog
    的不变量,而
    Cat
    可以安全地访问自己的
    protected
    成员,因为它知道如何确保自己的不变量

    细则:

    6.6.2.1访问受保护的成员

    设C为声明受保护成员m的类。仅允许在C的子类S的主体内访问。此外,如果Id表示实例字段或实例方法,则:

    • 如果访问是通过限定名Q.Id进行的,其中Q是ExpressionName,则当且仅当表达式Q的类型是S或S的子类时,才允许访问
    • 如果访问是通过字段访问表达式E.Id进行的,其中E是主表达式,或者通过方法调用表达式E.Id(…),其中E是主表达式,则当且仅当E的类型是S或S的子类时,才允许访问
    6.6.2.2有资格访问受保护的构造函数

    设C为声明受保护构造函数的类,设S为声明中使用受保护构造函数的最内层类。然后:

    • 如果访问是通过超类构造函数调用super(…)或通过形式为E.super(…)的限定超类构造函数调用进行的,其中E是主表达式,则允许访问
    • 如果访问是通过形式为new C(…){…}的匿名类实例创建表达式或形式为E.new C(…){…}的限定类实例创建表达式进行的,其中E是主表达式,则允许访问
    • 否则,如果通过形式为new C(…)的简单类实例创建表达式或形式为E.new C(…)的限定类实例创建表达式进行访问,其中E是主表达式,则不允许访问。受保护的构造函数只能由类实例创建表达式(不声明匿名类)从定义它的包中访问
    另请参见:


    您已经创建了一个Cat实例,并将其转换为其超类类型,即动物类型。根据动物类型,其测试方法在同一包装或任何亚型中可见。如果您没有强制转换为动物类型,代码将编译

    希望有帮助


    ./Arun

    在受保护的访问中,成员在同一个包中访问,对于继承的类,也可以访问另一个包中的成员


    在包访问中,可以访问同一包中的类的成员。在package access中无法访问其他包中的类成员。

    我想我理解了,但仍然需要一些时间来消化和理解。当重写时,我们是否必须维护方法签名,包括访问修饰符的签名?如果超类具有
    受保护的void get(){}
    并且重写它的子类不能具有
    void get(){}
    ,即默认访问权限。但是它可以有
    public void get(){}
    protected void get(){}
    @渴望学习-其背后的思想是子类总是可以使方法更容易访问,但不是更难访问;这样,子类仍然符合超类契约。换句话说,强制转换到超类永远不会让你访问更多的方法。你必须是一个猫才能使用testInstanceMethod()。对Animal的强制转换将对该方法的访问限制在lavel包中,因为main在不同的包中,所以代码失败。(我认为它甚至不会编译)。是的,方法在那里,但你没有权限访问它,正如受保护动物在《动物》中声明的那样。第二条声明应该表述为:“为了满足受保护级别的访问,两个条件中的一个
    Dog dog = new Dog();
    Animal cat = new Cat();
    
    dog.testInstanceMethod(); // Not allowed, because Cat should not be able to access protected members of Dog
    cat.testInstanceMethod(); // Not allowed, because compiler doesn't know that runtime type of cat is Cat
    
    ((Cat) cat).testInstanceMethod(); // Allowed