override that in AbstractBase, so it is AbstractBase.pac that show invokes. Both the pro and pub
methods are accessible in Concrete1 and get overridden, so the implementation from Concrete1 is used
in show.
Next we define the class Concrete2, which extends Concrete1 but is in the same package P1 as
AbstractBase:[2]
[2] Having an inheritance hierarchy that weaves in and out of a package is generally a very
bad idea. It is used here purely for illustration.
package P1;
import P2.Concrete1;
public class Concrete2 extends Concrete1 {
public void pri() { print("Concrete2.pri()"); }
public void pac() { print("Concrete2.pac()"); }
public void pro() { print("Concrete2.pro()"); }
public void pub() { print("Concrete2.pub()"); }
}
Each method of Concrete2 overrides the version from Concrete1 because they are all public and
therefore accessible. Also, because Concrete2 is in the same package as AbstractBase, the method
AbstractBase.pac is accessible in Concrete2 and so is overridden by Concrete2.pac. Invoking
show on a Concrete2 object prints
AbstractBase.pri()
Concrete2.pac()
Concrete2.pro()
Concrete2.pub()
Finally, we define the class Concrete3, which extends Concrete2 but is in a different package P3:
package P3;
import P1.Concrete2;
public class Concrete3 extends Concrete2 {
public void pri() { print("Concrete3.pri()"); }
public void pac() { print("Concrete3.pac()"); }
public void pro() { print("Concrete3.pro()"); }
public void pub() { print("Concrete3.pub()"); }
}
Invoking show on a Concrete3 object prints
AbstractBase.pri()
Concrete3.pac()
Concrete3.pro()
Concrete3.pub()