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

时间:2013-08-28 17:54:55

标签: java package protected access-modifiers

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

  1. Isn't "package private" member access synonymous with the default (no-modifier) access?

    在这个接受的答案中说

      

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

  2. Why the protected modifier behave differently here in Java subclass?

    在这个接受的答案中说

      

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

         
        
    • 这些类必须在同一个包中。
    •   
    • 必须有继承关系。
    •   
  3. 他们不矛盾吗?根据我对其他文章的理解,第一篇文章给出了正确的答案,即在其他包中保护== package-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();
            }
        }
    

    请说明上述代码失败的原因。那将非常有用。感谢

3 个答案:

答案 0 :(得分: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

这是有道理的,因为protected Dog的{​​{1}}成员访问可能会破坏Cat的不变量,而Dog可以访问自己的Cat protected 1}}成员安全,因为它知道如何确保自己的不变量。

详细规则:

  

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是主表达式,则允许访问。
  •   
  • 如果访问是通过新C(...){...}形式的匿名类实例创建表达式或由E.new C(...)形式的限定类实例创建表达式进行的。 ...},其中E是主表达式,然后允许访问。
  •   
  • 否则,如果访问是通过新C(...)形式的简单类实例创建表达式或通过形式为E.new C(...)的限定类实例创建表达式,其中E是一个主表达式,然后不允许访问。受保护的构造函数只能由定义它的包中的类实例创建表达式(不声明匿名类)访问。
  •   

另见:

答案 1 :(得分:3)

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

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

答案 2 :(得分:0)

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

希望有所帮助

./阿伦