Evaluating Method Invocations
This explanation
will use the following simplified example.
class A {
public void f() { System.out.println("
A-f"); }
public void h(A o) {
System.out.print("A-h"); }
public void m(A o) {
System.out.print("A-m"); }
}
class B extends A {
public void f() { System.out.println("
B-f"); }
public void h(A o) {
System.out.print("B-h"); }
public void m(B o) {
System.out.print("B-m"); }
}
public class
MT2Test1 {
public static void main(String[] args)
{
B b1 = new B();
B b2 = new B();
A a1 = new A();
A a2 = b2;
b1.m(a1);
a2.m(a2);
}
Algorithm for evaluating method invocations at compile-time:
·
Determine the declared class of the variable on
which the method is being called.
B
b1 = new B1();
...
b1.m(a1); // The declared type of b1 is B.
·
Start searching in that class for a method with the
same name and arguments that match in number and declared type of the objects
being passed in.
B
b1 = new B1();
A
a1 = new A1();
...
b1.m(a1); //
Search in B for a method called m that takes
//
as an argument a single A (or any superclass
//
of A).
·
Continue up the inheritance hierarchy looking for a
matching method in the same manner as above.
If not found, it is a compile-time error.
·
Write down the method descriptor of the method that
matches at compile-time. It will be
used in the runtime evaluation. A
method descriptor is the return type and signature of the method. Remember the signature is the name of the
method and the type and order of the arguments.
void
m(A) // write this down for use in
runtime step
Algorithm for evaluating method invocations at runtime:
·
Determine the type of the object to which the
variable is bound. Your search will
begin in this class.
·
Look for a method with the exact descriptor you
found earlier from the compile-time evaluation.
·
If found, you’re done. If not, continue up the inheritance hierarchy. You’re guaranteed to find an implementation.
Walkthrough #1
Compile-time
evaluation of b1.m(a1):
·
Declared class of b1
is B. Begin
search in this class.
·
Declared class of a1
is A. Look for
method called m in B
that takes a single A (or Object)
argument.
·
Matching method not found in B
so go to A.
Found match!
·
Write down the descriptor of the matching
method. void m(A)
Runtime evaluation
of b1.m(a1):
·
The type of the object bound to b1
is B. Begin
search in this class.
·
Look for method in B
with descriptor found in compile-time evaluation.
·
Matching method (void m(A)) not
found in B so go to A. Found match!
·
A’s version of m
is executed.
Walkthrough #2
Compile-time
evaluation of a2.m(a2):
· Declared class of a2 is A. Begin search in this class.
· Declared class of a2 is A. Look for method called m in A that takes a single A (or Object) argument.
· Found match!
· Write down the descriptor of
the matching method. void
m(A)
Runtime evaluation
of a2.m(a2):
· The type of the object bound
to a2 is B. Begin search in this class.
· Look for method in B with descriptor found in
compile-time evaluation.
· Matching
method (void m(A)) not found in B
so go to A.
Found match!
· A’s
version of m is executed.
Further Reading
The source for this
material was the Java
Language Specification – 15.12 Method
Invocation Expressions. Note that
the steps here are vastly simplified.