首页 文章

Java中的protected和package-private访问修饰符之间的区别? [重复]

提问于
浏览
27

这个问题在这里已有答案:

我已经看过有关protected和package private修饰符之间差异的各种文章 . 有一件事我发现这两个帖子之间存在矛盾

在这个被接受的答案说

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

在这个被接受的答案说

要满足受保护级别访问,必须满足两个条件:类必须位于同一个包中 . 必须有继承关系 .

他们不矛盾吗?根据我对其他文章的理解,第一篇文章给出了正确的答案,即在其他包中保护== package-private子类 .

如果此语句是正确的,那么为什么此代码失败,并在第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();
        }
    }

请说明上述代码失败的原因 . 这将非常有用 . 谢谢

3 回答

  • 24

    第一个答案基本上是正确的 - 可以通过访问 protected 成员

    来自同一个包的

    • 个类

    • 来自其他包的声明类的子类

    但是,有一个小技巧:

    6.6.2受保护访问的详细信息对象的受保护成员或构造函数可以从仅在负责实现该对象的代码声明它的包外部进行访问 .

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

    例如(假设此代码在 Cat 中):

    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
    

    这是有道理的,因为通过 Cat 访问 Dogprotected 成员可能会破坏 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为其中的一个类声明了protected构造函数,让S成为声明使用受保护构造函数的声明中最内层的类 . 然后:如果访问是通过超类构造函数调用super(...)或通过形式为E.super(...)的限定超类构造函数调用,其中E是主表达式,则允许访问 . 如果访问是通过新C(...)形式的匿名类实例创建表达式,或者是由E.new C(...)形式的限定类实例创建表达式{...其中E是主表达式,然后允许访问 . 否则,如果访问是通过新C(...)形式的简单类实例创建表达式或通过形式为E.new C(...)的限定类实例创建表达式,其中E是主表达式,然后不允许访问 . 受保护的构造函数只能由定义它的包中的类实例创建表达式(不声明匿名类)访问 .

    See also:

  • 0

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

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

  • 2

    您已经创建了一个Cat实例并将其强制转换为超类类型,即Animal类型 . 根据Animal类型,其testInstanceMethod在同一个包或任何子类型中可见 . 如果你没有转换为Animal类型,代码将编译 .

    希望有所帮助

    ./Arun

相关问题