Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

difference between protected and package-private access modifiers in Java? [duplicate]

I have seen various articles on differences between the protected and package private modifiers. One thing I found contradictory between these two posts

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

    In this the accepted answer says that

    The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.

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

    In this the accepted answer says that

    To satisfy protected level access two conditions must be met:

    • The classes must be in the same package.
    • There must be an inheritance relationship.

Aren't they contradictory? from my understanding of other articles, the first post gives the correct answer that protected == package-private + subclass in other package.

If this statement is correct, then why this code fails with the following error message on my subclass Cat on line 17

The method testInstanceMethod() from the type Animal is not visible  

my code for super and subclass are below.

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();         }     } 

Please clarify why the above code fails. That would be very useful. Thanks

like image 330
eagertoLearn Avatar asked Aug 28 '13 17:08

eagertoLearn


People also ask

What is the difference between protected and package private in Java?

The private modifier specifies that the member can only be accessed in its own class. The protected modifier specifies that the member can only be accessed within its own package (as with package-private) and, in addition, by a subclass of its class in another package.

What is difference between package and private access modifiers?

Private modifier is the most restricted modifier among all modifiers. Protected modifier is more accessible than the package and private modifier but less accessible than public modifier. Package modifier is more restricted than the public and protected modifier but less restricted than the private modifier.

Is package private the same as protected?

package-private is the default access modifier and does not have a keyword, because package is used to specify the package for a class or interface. To declare package access for something, use no access modifier. protected indicates that only descendants of the class can access the item.

What is the difference between public/private and protected access modifiers in Java?

Differences. First and important difference is the accessibility i.e. anything public is accessible to anywhere , anything private is only accessible in the class they are declared , anything protected is accessible outside the package but only to child classes and default is accessible only inside the package.


1 Answers

The first answer is basically correct - protected members can be accessed by

  • classes from the same package
  • subclasses of the declaring class from other packages

However, there is a little trick:

6.6.2 Details on protected Access

A protected member or constructor of an object may be accessed from outside the package in which it is declared only by code that is responsible for the implementation of that object.

It means that subclass from other package cannot access protected members of arbitrary instances of their superclasses, they can only access them on instances of their own type (where type is a compile-time type of expression, since it's a compile-time check).

For example (assuming that this code is in 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 

It makes sense, because accessing of protected members of Dog by Cat may break invariants of Dog, whereas Cat can access its own protected members safely, because it knows how to ensure its own invariants.

Detailed rules:

6.6.2.1 Access to a protected Member

Let C be the class in which a protected member m is declared. Access is permitted only within the body of a subclass S of C. In addition, if Id denotes an instance field or instance method, then:

  • If the access is by a qualified name Q.Id, where Q is an ExpressionName, then the access is permitted if and only if the type of the expression Q is S or a subclass of S.
  • If the access is by a field access expression E.Id, where E is a Primary expression, or by a method invocation expression E.Id(. . .), where E is a Primary expression, then the access is permitted if and only if the type of E is S or a subclass of S.

6.6.2.2 Qualified Access to a protected Constructor

Let C be the class in which a protected constructor is declared and let S be the innermost class in whose declaration the use of the protected constructor occurs. Then:

  • If the access is by a superclass constructor invocation super(. . .) or by a qualified superclass constructor invocation of the form E.super(. . .), where E is a Primary expression, then the access is permitted.
  • If the access is by an anonymous class instance creation expression of the form new C(. . .){...} or by a qualified class instance creation expression of the form E.new C(. . .){...}, where E is a Primary expression, then the access is permitted.
  • Otherwise, if the access is by a simple class instance creation expression of the form new C(. . .) or by a qualified class instance creation expression of the form E.new C(. . .), where E is a Primary expression, then the access is not permitted. A protected constructor can be accessed by a class instance creation expression (that does not declare an anonymous class) only from within the package in which it is defined.

See also:

  • Java Language Specification
like image 177
axtavt Avatar answered Sep 22 '22 22:09

axtavt