简体   繁体   中英

Java access to protected member in subclass in different package, using object reference of parent type

I have the following code in two separate files.

package animal;

public class Frog
{
    protected void ribbit()
    {
        System.out.println("In Frog class!");
    }
}





package other;

import animal.*;

public class Tadpole extends Frog

{
    protected void ribbit()
    {
        System.out.println("In Tadpole class!");
    }

    public static void main(String[] args)
    {
        Tadpole t = new Tadpole();
        t.ribbit();

        Frog f = new Tadpole();
        f.ribbit(); // Does not compile
    }
}

The first Tadpole object assigned to Tadpole type obviously compiles fine and the call to ribbit() will be to the Tadpole 's ribbit() implementation. The second Tadpole object that is created and assigned to a Frog reference. However, the call to ribbit() results in a compiler error.

I know that if you create a subclass object in the subclass and assign to a superclass reference that is outside of the subclass's package and try to call a superclass method, this is not allowed. But in this case, shouldn't polymorphism make the object reference "f" call the Tadpole 's ribbit() method since a Tadpole object was assigned to it? Why does this cause a compiler error and why is this is not allowed?

This is related to the rules about access to protected class members. See this section from the Java Language Specification on details, specifically:

Let C be the class in which a protected member 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 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.

  • If the access is by a field access expression E.Id, or a method invocation expression E.Id(...), or a method reference expression E :: Id, where E is a Primary expression (§15.8), then the access is permitted if and only if the type of E is S or a subclass of S .

So within the body of a subclass of Frog , you can only access x.ribbit() if x is a subclass of Frog ( x cannot be declared a Frog ).

This restriction exists on protected members, because otherwise, imagine that Frog has a protected int field:

public class Frog {
    protected int a = 1;

    ...
}

Then one would be able to define a public method in the subclass of Frog :

public class TadPole extends Frog {

    public int revealFieldValueOfParent(Frog frog) {
        return frog.a;  // imagine this was OK
    }
}

Then any other (unrelated) class would be able to access the field by passing a Frog to the method of the subclass:

public class SomeOtherClass {

    public static void main(String[] args) {
         TadPole tadpole = new TadPole();
         Frog frog = new Frog();
         int revealedValue = tadpole.revealFieldValueOfParent(frog);
         // print revealedValue
    }
}

EDIT:

This compiler error has nothing to do with polymorphism. Polymorphism, as related to the actual type of the object, is a runtime aspect and the compiler does not try to think whether at runtime the variable f actually refers to a Frog or to a Tadpole . All the compiler is doing here is enforcing the rules of the protected modifier, nothing more.

EDIT 2:

Based on the comments below, the revealFieldValueOfParent(Frog frog) method would actually reveal the value of the protected if we change it to revealFieldValue(TadPole frog) , but you can also do that revealing trick with private members (ie similar to a getter method). It would really become the responsibility of the subclass to know what it's doing.

protected limits access to Class , package , or subclass as long as the subclass is declared as type of subclass and not the superclass.

eg if Frog and Tadpole are in different packages , Frog f = new Tadpole(); does not work if you want to access Frog 's ribbit method, but Tadpole f = new Tadpole(); does

Just for simple understanding, method overriding is runtime feature . This is obtained in run time and compiler do not care about this during compilation. So your code has to be compiler compliance . So your compilation fails because the method is not accessible from other package during compilation ( despite the fact that it would be available during run time as it inherits the Frog class).

受保护的访问修饰符 - 在超类中声明受保护的变量,方法和构造函数只能由其他包中的子类或受保护成员类的包中的任何类访问。

When you are trying to call method from Frog object, at compile time it looks only for Frog class method prototype and it is declared as protected which is not visible outside Frog class. Hope this helps you

Thank you for all of your responses. Based on some of the responses, I think I've figured out why this does not compile. I'm posting a separate response to make it completely clear and will clarify which things don't have access with respect to what since I felt that many of the responses only contained snippets of the explanation.

Frog f = new Tadpole();
f.ribbit(); // does not compile

The above does not compile because although the Tadpole object is created in the Tadpole class itself and is calling Tadpole's ribbit() method, it is called using a Frog object reference. Here we have a subclass that is assigned to a superclass reference and because of polymorphism, the Frog object reference "f" will attempt to call Tadpole's ribbit() method. However, because ribbit() is protected and Frog is NOT a subclass of Tadpole, an object reference of type Frog cannot access a protected method defined in Tadpole. This is why the code does not compile.

Again, this is confusing because Tadpole is a subclass of Frog and all calls are being made in the subclass Tadpole. The thing to note though is that the call itself is being made using an object reference "f" which is of type Frog that is attempting to access a protected method from Tadpole and Frog is NOT a subclass of Tadpole.

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