Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can a derived class invoke private method of base class?

public class PrivateOverride {  

    private void f() {  
        System.out.println("private f()");  
    }
}  

public class Derived extends PrivateOverride {  

    public void f() {                         //this method is never run.
        System.out.println("public f()");     
    }  
}  

public static void main(String[] args) {

    // instantiate Derived and assign it to 
    // object po of type PrivateOverride.
    PrivateOverride po = new Derived();  

    // invoke method f of object po.  It
    // chooses to run the private method of PrivateOveride
    // instead of Derived
    po.f();                         
  }  
}  

So, the output of this code is private f(). Now, the question arises to my mind: how can po which is an object of Derived Class call a private method of PrivateOverride which is its base class?

like image 249
Saurab Parakh Avatar asked Jan 09 '14 09:01

Saurab Parakh


People also ask

Can a derived class directly invoke a private method of the base class java?

Yes. A java private member cannot be inherited as it is available only to the declared java class.

Can derived class access private methods?

say() because derived classes can't inherit private methods from its base class. Only protected and public methods/variables can be inherited and/or overridden.

Can private methods in a derived class call private methods in the base class?

Can private methods in a derived class call private methods in the base class? -Yes, if the methods are declared const in the base class.

How does a derived class can get access privilege for a private member of the base class?

Private members of the base class cannot be used by the derived class unless friend declarations within the base class explicitly grant access to them. In the following example, class D is derived publicly from class B . Class B is declared a public base class by this declaration.


6 Answers

Because you defined the main method in PrivateOverride class. If you put the main method in Derived class, it would not compile, because .f() would not be visible there.

po.f() call in PrivateOverride class is not a polymorphism, because the f() in PrivateOverride class is private, so f() in Derived class is not overriden.

like image 71
Péter Szakszon Avatar answered Oct 05 '22 22:10

Péter Szakszon


I do not really see the problem. That method is called ""within"" the class, this is pretty much expected. This method is not overidden at all, instead it is shadowed by another one.

like image 23
Eugene Avatar answered Oct 05 '22 22:10

Eugene


Methods in Java are dispatched depending on the static type of the receiver, which in this case is a PrivateOverride. Do not be confused by the fact that the po variable, by examining the code, can only hold a Derived instance at that line: only the declaration matters when available methods are searched.

And, by the way, the call to f() is not even translated into a virtual call in the final bytecode, because when the compiler looks for the potentially applicable methods in the class PrivateOverride, it only finds Object methods and the f() definition, which is only visible because the main() method is defined in PrivateOverride itself (see JLS 15.12)

like image 45
Raffaele Avatar answered Oct 06 '22 00:10

Raffaele


I just went through the byte code of the compiled version of the above class and got the invokespecial Opcode. This Opcode was enough to tell the reason why the actual output is obvious. Invokespecial is used in three situations in which an instance method must be invoked based on the type of the reference, not on the class of the object. The three situations are:

1)invocation of instance initialization () methods

2)invocation of private methods

3)invocation of methods using the super keyword

Above example lies within the second scenario where we have invocation of private methods. So the method got invoked based on the the type of reference i.e PrivateOverride rather than type of class i.e Derived

So now the question arises why invokespecial? We have other Opcode like invokevirtual which gets invoked for method on the basis of classtype rather than reference type. So lets discuss why invokespecial Opcode is used for private methods. But we should know the difference between invokevirtual and invokespecial. Invokespecial differs from invokevirtual primarily in that invokespecial selects a method based on the type of the reference rather than the class of the object. In other words, it does static binding instead of dynamic binding. In each of the three situations where invokespecial is used, dynamic binding wouldn't yield the desired result.

like image 40
evaipar Avatar answered Oct 05 '22 23:10

evaipar


When a method is invoked the JVM has to figure out what piece of code to execute: sometimes this is done at runtime (e.g. when overriding methods); sometimes this is done at compile time (e.g. when overloading methods). Once the JVM resolves what bit of code it is executing the actual instance that you are referring to isn't really any more significant than any other parameter.

The example code given sets up a scenario that may look like method overriding but isn't, so the method ends up getting bound at compile time. The private visibility modifier is not violated because the invocation doesn't touch any of Derived's code.

Looking at the bytecode (which the Java code is compiled to via javac) is instructive -

Say we slightly modify the original code to:

public class PrivateOverride {
private void f() {
    System.out.println("private f()");
}

public static void main(String[] args) {
    PrivateOverride po = new Derived();
    po.f();
    Derived d = new Derived();
    d.f();
}
}

class Derived extends PrivateOverride {
public void f() {
    System.out.println("public f()");
}
}

The main method compiles to (edited for brevity):

public static main([Ljava/lang/String;)V
  NEW Derived
  DUP
  INVOKESPECIAL Derived.<init>()V
  ASTORE 1
  ALOAD 1
  INVOKESPECIAL PrivateOverride.f()V
  NEW Derived
  DUP
  INVOKESPECIAL Derived.<init>()V
  ASTORE 2
  ALOAD 2
  INVOKEVIRTUAL Derived.f()V
  RETURN

Notice that in each case the method is invoked on the compile time type. Notice also that the second call of f() uses the INVOKEVIRTUAL instruction. This is what tells the JVM to check the runtime type and decide what to call based on that.

like image 26
CurtainDog Avatar answered Oct 05 '22 22:10

CurtainDog


It behaves this way because that is how the JVM was defined to behave in those cases.

The hard part is understanding what is going on and why.

You invoked the private method from within the class in which it was private. So the trojan horse is inside the castle, he can fiddle with the private variables. Take the trojan horse out of the castle and the private method is no longer visible.

This example might clear things up, Consider this program:

public class Bicycle {  
  private void getCost() {  
      System.out.println("200");  
  }  

  public static void main(String[] args) {  
      Bicycle ACME_bike = new ACME_bike();
      ACME_bike.getCost();

      Bicycle mybike = new Bicycle();
      mybike.getCost();

      ACME_bike acme_bike = new ACME_bike();
      acme_bike.getCost();

      //ACME_bike foobar = new Bicycle(); //Syntax error: Type mismatch: 
                                          //cannot convert from 
                                          //Bicycle to ACME_bike
  }  
}  

class ACME_bike extends Bicycle {
  public void getCost(){
      System.out.println("700");
  }
}

This program prints:

200
200
700

If you change the access modifier of getCost within Bicycle to public, protected, or package private(no modifier), Then it prints this:

700
200
700
like image 29
Eric Leschinski Avatar answered Oct 05 '22 23:10

Eric Leschinski