13.4.6 Access to Members and Constructors

Changing the declared access of a member or constructor to permit less access may break compatibility with pre-existing binaries, causing a linkage error to be thrown when these binaries are resolved. Less access is permitted if the access modifier is changed from default access to private access; from protected access to default or private access; or from public access to protected, default, or private access. Changing a member or constructor to permit less access is therefore not recommended for widely distributed classes.

Perhaps surprisingly, Java is defined so that changing a member or constructor to be more accessible does not cause a linkage error when a subclass (already) defines a method to have less access. So, for example, if the package points defines the class Point:

package points;


public class Point {
	public int x, y;
	protected void print() {
		System.out.println("(" + x + "," + y + ")");
	}
}

used by the Test program:


class Test extends points.Point {
	protected void print() { System.out.println("Test"); }
	public static void main(String[] args) {
		Test t = new Test();
		t.print();
	}
}

then these classes compile and Test executes to produce the output:

Test

If the method print in class Point is changed to be public, and then only the Point class is recompiled, and then executed with the previously existing binary for Test then no linkage error occurs, even though it is improper, at compile time, for a public method to be overridden by a protected method (as shown by the fact that the class Test could not be recompiled using this new Point class unless print were changed to be public.)

Allowing superclasses to change protected methods to be public without breaking binaries of preexisting subclasses helps make Java binaries less fragile. The alternative, where such a change would cause a linkage error, would create additional binary incompatibilities with no apparent benefit.