Search code examples
javainheritanceprivate-methods

Private method defined in `Sub` and `Super`, both methods can be invoked on Object of Sub , then why private method said not being inherited?


As per Oracle Tutorials

A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.

[Question] For a class relationship as Sub extends Super, It's understood that The Oracle docs say so just to support the fact "only inherited methods can be overridden" but then it is kind of misleading statement, as if it seems to imply => if a method is not inherited then it is not present as a behavior of the object of Sub class and if so then it can in no way be invoked on an object of Sub class. But a method in class Super can invoke the private method defined by Class Super on an Object of Sub class. Please refer below points and related code and suggest if there some gap in my understanding ?

I have always understood the inheritance as below 3 points

  1. A class Sub inherits all instance methods and fields (including the private).
  2. If a method is private in Super then it is not visible in Sub but this does not mean that an object of Sub does not have the behavior.

Code for point 1 and 2

public class Super{
    private void privateMethod(){
        System.out.println("private method defined in Super");
    }
    public void m(){
        privateMethod();
    }
}

public class Sub extends Super{

} 
public void Other{
    public static void main(String[] args){
        Sub s = new Sub();
        s.m(); 
    }
}

We have created an object of Sub, m() is inherited by Sub and its public meaning it can be accessed by code outside Super. On invoking m() we are able to invoke privateMethod(). If private methods were not inherited then some run time exception would have occurred which is not the case.

  1. Overriding is applicable to visible instance methods in Sub class only. If a method is not visible an is defined in both classes, Sub and Super, then the object has both the capabilities and both the methods can be invoked by the code which can access the particular method ( refer code below)

Code for point 3

public class Super{
    private void privateMethod(){
        System.out.println("private method defined in Super");
    }
    public void m(){
        privateMethod();
    }
}

public class Sub extends Super{
    private void privateMethod(){
        System.out.println("private method defined in Sub");
    }
    public void m2(){
        privateMethod();
    }
} 
public class Other{
    public static void main(String[] args){
        Sub s = new Sub();
        s.m(); // m() will invoke private method of Super
        s.m2(); // m2() will invoke private method of Sub
    }
}

Saying that Sub class does not inherits private method from Super implies method can not be invoked on an object of Sub as the behavior is not inherited, hence not part of ( does not belongs to) the object. Above we see it is not the case.


Solution

  • I think the key difference is in how the Java Language Specification uses the term "inherit". (Note that the JLS is the authoritative documentation, not the Java tutorials.)

    JLS 8.2, Class Members says:

    Members of a class that are declared private are not inherited by subclasses of that class.

    But, when describing the behavior of the new operator, JLS 15.9.4, Run-Time Evaluation of Class Instance Creation Expressions says (emphasis mine):

    The new object contains new instances of all the fields declared in the specified class type and all its superclasses.

    This means that the superclass fields are not inherited by the subclass, but an instance object of the subclass still contains those fields. The same concept applies to private methods as well.

    Although a private method from a superclass can be called on an instance of a subclass, the method is not formally a part of that subclass. The private method still belongs to the superclass.

    This works because of the subtyping ("is-a") relationship. An instance of the subtype is an instance of the supertype. The class does not inherit those members into itself, but an instance of the class still contains them.