简体   繁体   中英

Sub-class not able to access the protected method of super-class when the reference is of type super-class

Parent class

package p1;

public class A {
    protected void display() {
        System.out.println("Displayed");
    }
}

Child class (in another package)

package p2;

import p1.A;

public class B extends A {
    public static void main(String[] args) {
        A a = new B();
        a.display();
    }
}

In the child class, if I write B a = new B() , it works fine and displays "Displayed".

But, the above piece of code in child class where A a = new B() is written, it throws compile time error as 'display()' has protected access in 'p1.A'

I am confused with the protected access modifier now as how it works when the reference type is of parent?

As I wrote in a comment, you can do this:

package p2;

import p1.A;

public class B extends A {

    public static void main(String[] args) {
        B a = new B();
        a.foo();
    }

    public void foo() {
        display(); // works
        super.display(); // same, but more wordy
        A a = (A)this;
        a.display(); // NOT working !!!
    }

    public void bar(A a) {
        a.display(); // NOT working !!!
    }
}

display() , can be called from subclass (static method is not member method) or in same package like this

package p1;

public class C {

    public static void main(String[] args) {
        A a = new A();
        a.display();
    }

}

hm, those

a.display(); // NOT working !!!

are something not really clear to me, see discussion

A a = new B(); doesn't work because the reference type of a is A and A doesn't expose display() to another package.

take this example:

public void method(A a){ // defined in some class in a different package
   a.display(); // can't be called from different package as reference type is `A`
}

the compiler here has no way to know whether you'll assign a A or a subtype of A and hence it bails out.

It will be easier to understand if you forget your example for a second and just focus on the method i've created, notice that i'm saying it's in a class defined in a different package. now ask yourself can i call display() on A from a different package, obviously not it's a protected method.

Here is the relevant Language Specification paragraph:

If the access is by a qualified name Q.Id or a method reference expression Q :: Id (§15.13), 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.

( 6.6.2.1. Access to a protected Member )

In your case, Q is a , and S is B . Since the type of Q is not a subclass of B the access is not permitted.

For the explanation on why this restriction was introduced, see Checking Access to Protected Members in the Java Virtual Machine (search for Requirements on Protected Members )

The motivation behind the restriction on protected access is to prevent almost arbitrary access to protected members of objects [Yel02]. Suppose that m is a protected, nonstatic field declared in c. Without the restriction, any class x could read the content of the field m of any object of class c, using the following trick: define a subclass s of c (the trick works only if c is not final, hence the “almost” adverb above); declare a method in s that takes an object of class c as argument and returns the content of its m field; and have x call this method. The restriction on protected access prevents this situation, because s can access the field only if the class o of the object satisfies o ≤ s

Protected methods can only be accessible through inheritance in subclasses outside the package

display will be accessible to every subclass AND every class in the same package.

display will be accessible to every class in the same package (not available in children class if there are in a different package)

A a = new B(); will not work because the reference type of a is A and A will not exposing display() to another package.

Below code will work:

package p2;

import p1.A;

public class B extends A {
    public static void main(String[] args) {
        B a = new B();
        a.demo();
    }

    public void demo(){
        display();
    }
}

I think from the link: http://tutorials.jenkov.com/java/access-modifiers.html important statement is

The protected access modifier provides the same access as the default access modifier, with the addition that subclasses can access protected methods and member variables (fields) of the superclass.

Here, subclass means subclass reference type only. For parent reference type, the only option left is public.

It is kind of unstated hidden rule. Even the IDEs are suggesting to change it to public to access via parent's reference. Weird!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM