The following contrived example should make this clearer. Suppose we have a class AbstractBase
declared in package P1:
package P1;
public abstract class AbstractBase {
private void pri() { print("AbstractBase.pri()"); }
void pac() { print("AbstractBase.pac()"); }
protected void pro() { print("AbstractBase.pro()"); }
public void pub() { print("AbstractBase.pub()"); }
public final void show() {
pri();
pac();
pro();
pub();
}
}
We have four methods, each with a different access modifier, each of which simply identifies itself. The
method show invokes each of these methods on the current object. It will show which implementation of
each method is invoked when applied to different subclass objects.
Now we define the class Concrete1, which extends AbstractBase but lives in the package P2:
package P2;
import P1.AbstractBase;
public class Concrete1 extends AbstractBase {
public void pri() { print("Concrete1.pri()"); }
public void pac() { print("Concrete1.pac()"); }
public void pro() { print("Concrete1.pro()"); }
public void pub() { print("Concrete1.pub()"); }
}
This class redeclares each of the methods from the superclass and changes their implementation to report that
they are in class Concrete1. It also changes their access to public so that they are accessible to all other
code. Executing the code
new Concrete1().show();
produces the following output:
AbstractBase.pri()
AbstractBase.pac()
Concrete1.pro()
Concrete1.pub()
Because the private method pri is inaccessible to subclasses (or to any other class) the implementation from
AbstractBase is always the one invoked from show. The package accessible pac method of
AbstractBase is not accessible in Concrete1, thus the implementation of pac in Concrete1 does not