5

I am calling a super class' protected method from a subclass. Why is this method "not visible"?

I've been reading some posts such as this one, that seem to contradict the following:

Super class:

package com.first;

public class Base
{
    protected void sayHello()
    {
        System.out.println("hi!");
    }
}

Subclass:

package com.second;

import com.first.Base;

public class BaseChild extends Base
{
    Base base = new Base();

    @Override
    protected void sayHello()
    {
        super.sayHello(); //OK :)
        base.sayHello(); //Hmmm... "The method sayHello() from the type Base is not visible" ?!?
    }   
}
Community
  • 1
  • 1
rapt
  • 11,810
  • 35
  • 103
  • 145
  • http://stackoverflow.com/a/19949354/868975 – Bax Mar 24 '16 at 01:23
  • Same as this one perhaps: http://stackoverflow.com/questions/36093187/accessing-protected-member-of-static-class-in-subclass-of-the-parent#comment59830891_36093187 – aioobe Mar 24 '16 at 06:03

3 Answers3

11

base is a variable that is not special in any way: it's not part of a class hierarchy and protected access is not available through it. Even though sayHello has access to protected members of Base, it has that access only through inheritance (since it's not in the same package: the protected keyword allows access via both inheritance and package, see the table in this Oracle tutorial).

Access through this and super is allowed because those are part of the inheritance hierarchy.

Paul Hicks
  • 13,289
  • 5
  • 51
  • 78
  • 3
    I think you are the only one here that noticed that `base` was just a variable. – Scary Wombat Mar 24 '16 at 01:22
  • 2
    I think I need better terminology though.. I know what I'm trying to say, but I think there are better-accepted terms out there that I can't currently remember.. – Paul Hicks Mar 24 '16 at 01:23
  • This is still surprising, since you can call private methods on any instance of the currently declared class (`this` and any instance other than `this`). The following code works: `public class A { private void b() { new A().b(); }}` – Stefan Dollase Mar 24 '16 at 01:27
  • @StefanDollase, that's inside `A` though. Of course, `A`'s private methods are available to `A`. – ChiefTwoPencils Mar 24 '16 at 01:30
  • @ChiefTwoPencils Yes, but it is still the same argument: The answer says it does not work, because it is the same inheritance hierarchy but not the same instance. I showed that in the case of the `private` modifier it is enough to be in the same inheritance hierarchy (consisting of only the type itself). For `private`, it does not matter if it is the same instance. I only pointed out that I am surprised by the divergent behavior. – Stefan Dollase Mar 24 '16 at 01:32
  • 1
    The difference is that it's the same class. There is no subclass involved. See dasblinkenlight's quote for more specific detail. – Paul Hicks Mar 24 '16 at 01:34
  • 1
    @StefanDollase, I read it differently. Sounds correct and not the same as your example. The main difference is OP is trying to use an *instance* of the parent as if it's `this`. If it had been in another class then, yes, that would be very surprising. – ChiefTwoPencils Mar 24 '16 at 01:37
  • Just to be clear: I am not surprised by the behavior of `private` but by the behavior of `protected`. I would have expected that the `protected` modifier has a similar behavior as `private` with respect to the situation described above. However, I seem to be the only one who is surprised, so never mind :-P – Stefan Dollase Mar 24 '16 at 01:47
  • @ChiefTwoPencils But how would you access private stuff in another class? I agree with Stefan Dollase that it's somewhat inconsistent. – rapt Mar 24 '16 at 01:48
  • @rapt, it's inconsistent by design. You *don't* access private stuff (directly or without "magic") in another class whether inherited or otherwise; it wouldn't be private then. If the way it works goes against your design, then perhaps the design needs some more thought. – ChiefTwoPencils Mar 24 '16 at 01:54
  • @ChiefTwoPencils I am not talking about accessing private stuff from another type. I think you still missed my point: For `private` you need to be in the same declaring class **but** you can use `private` stuff from **other instances** than `this`. For `protected` you need to be in the same class hierarchy as the declaring class **and** you can **only** use `protected` stuff from `this`. – Stefan Dollase Mar 24 '16 at 02:19
  • @StefanDollase, sorry, I understand what you're saying but failing to see what's surprising about it. Even if you had another instance of the class, you're still in the same class. While that may seem inconsistent, and maybe, by definition, it is, it makes total sense (to me). Aside from being inside the class which ensures no privacy is being violated, some things like recursive definitions may be impossible or unnecessarily difficult. Think of a BinaryTreeNode that wouldn't have access to the private stuffs its refs hold. That would be *shocking* to me. All opinion :) – ChiefTwoPencils Mar 24 '16 at 02:27
  • 1
    @ChiefTwoPencils As I said, I am not surprised by the behavior of private but by the behavior of protected. So the question is not why it is allowed for private but why it is not allowed for protected. Let's transfer your example of the algorithm which uses private methods on other instances than `this` to the protected version: Why can I not implement an algorithm which uses protected methods from the current inheritance hierarchy but on another instance than `this`? Why can I not access the protected methods of the parent class of the child nodes in a BinaryTreeNode? – Stefan Dollase Mar 24 '16 at 03:00
  • @ChiefTwoPencils I will stop this here, since this is a topic for another question. Cheers! – Stefan Dollase Mar 24 '16 at 03:02
  • @Stefan, for the record, I'm on my phone and missed your clarifying comment. Sorry, until next time... – ChiefTwoPencils Mar 24 '16 at 03:04
3

This is the correct behavior. In fact, Java Language Specification, section , 6.6.2-1, has an example very similar to yours, with a comment that it should not compile.

The specifics of accessing protected members are detailed in section 6.6.2.1:

6.6.2.1. Access to a protected Member

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, 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.

It's the last paragraph that describes why the access should be denied. In your example, C is Base, S is BaseChild, and E, the type of variable base, is also Base. Since Base is neither a BaseChild nor a subclass of BaseChild, the access is denied.

Community
  • 1
  • 1
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • While I understand that this prevents the access via `base` I don't see how it permits access via `super`. Isn't `super` of the same type as `base`? Maybe I missed something in the JLS? Is it permitted in another part of the JLS? I was not able to find a section which permits it. – Stefan Dollase Mar 24 '16 at 02:47
  • 1
    @StefanDollase That's the thing, `super` is not a field, it's a keyword that lets you access methods of the base class overridden in your class. However, the actual reference is done through `this`, not through a different variable. – Sergey Kalinichenko Mar 24 '16 at 03:17
-4

The keyboard protected is for visibility on the same package. If the child class is not of the same package, the protected methods of parent is not visible to the child class.

Dust Francis
  • 344
  • 3
  • 5
  • To explain the down votes: "The **[keyboard](https://en.wikipedia.org/wiki/Keyboard)**" is a device to enter characters into a computer. "protected is for visibility on the same package" - **in** the same package, but I digress. `protected` is mainly used to grant access to subclasses. "If the child class is not of the same package" - in the same... "the protected method of the parent is not visible to the child class." No. Access from the subclass is the entire point of `protected`. You probably mean the default visibility, which the `protected` access includes. – Johannes Kuhn Jul 15 '18 at 16:37