No incompatibility with pre-existing binaries is caused by adding a class member that has the same name (for fields) or same name, signature, and return type (for methods) as a member of a superclass or subclass. References to the original field or method were resolved at compile time to a symbolic reference containing the name of the class in which they were declared. This makes compiled Java code more robust against changes than it might otherwise be. No error occurs even if the set of classes being linked would encounter a compile-time error. As an example, if the program:
class Hyper { String h = "Hyper"; } class Super extends Hyper { } class Test extends Super { public static void main(String[] args) { String s = new Test().h; System.out.println(s); } }
is compiled and executed, it produces the output:
Hyper
Suppose that a new version of class Super
is then compiled:
class Super extends Hyper { char h = 'h'; }
If the resulting binary is used with the existing binaries for Hyper
and Test
, then
the output is still:
Hyper
even though compiling the source for these binaries:
class Hyper { String h = "Hyper"; } class Super extends Hyper { char h = 'h'; } class Test extends Super { public static void main(String[] args) { String s = new Test().h; System.out.println(s); } }
would result in a compile-time error, because the h
in the source code for main
would now be construed as referring to the char
field declared in Super
, and a
char
value can't be assigned to a String
.
Deleting a class member or constructor that is not declared private
may cause a linkage error if the member or constructor is used by a pre-existing binary, even if the member was an instance method that was overriding a superclass method. This is because, during resolution, the linker looks only in the class that was identified at compile time. Thus, if the program:
class Hyper { void hello() { System.out.println("hello from Hyper"); } } class Super extends Hyper { void hello() { System.out.println("hello from Super"); } } class Test { public static void main(String[] args) { new Super().hello(); } }
is compiled and executed, it produces the output:
hello from Super
Suppose that a new version of class Super
is produced:
class Super extends Hyper { }
If Super
and Hyper
are recompiled but not Test
, then a NoSuchMethodError
will result at link time, because the method hello
is no longer declared in class
Super
.
To preserve binary compatibility, methods should not be deleted; instead, "forwarding methods" should be used. In our example, replacing the declaration of Super
with:
class Super extends Hyper { void hello() { super.hello(); } }
then recompiling Super
and Hyper
and executing these new binaries with the
original binary for Test
, produces the output:
hello from Hyper
as might have naively been expected from the previous example.
The super
keyword can be used to access a method declared in a superclass, bypassing any methods declared in the current class. The expression:
super.
Identifier
is resolved, at compile time, to a method M declared in a particular superclass S.
The method M must still be declared in that class at run time or a linkage error will
result. If the method M is an instance method, then the method MR invoked at run
time is the method with the same signature as M that is a member of the direct
superclass of the class containing the expression involving super
. Thus, if the
program:
class Hyper { void hello() { System.out.println("hello from Hyper"); } } class Super extends Hyper { } class Test extends Super { public static void main(String[] args) { new Test().hello(); } void hello() { super.hello(); } }
is compiled and executed, it produces the output:
hello from Hyper
Suppose that a new version of class Super
is produced:
class Super extends Hyper { void hello() { System.out.println("hello from Super"); } }
If Super
and Hyper
are recompiled but not Test
, then running the new binaries
with the existing binary of Test
produces the output:
hello from Super
as you might expect. (A flaw in some early versions of Java caused them to print:
hello from Hyper