Polymorphism and Dynamic Dispatch
Objectives
This lab introduces you to the concepts of polymorphism in Java. You are going to start with the inheritance hierarchy from a previous lab (with minor changes).
-
Study code to gain a deeper understanding of Polymorphism.
-
Construct a mechanism for Dynamic Dispatch by working with reflection.
Getting Started
-
Create a project called L8 and download DynamicDispatch-starter archive:
Your directory structure will look like this:
L8/ └── src ├── A.java ├── B.java ├── C.java ├── DynamicDispatch.java └── TestCode.java
Part One
Go to the DynamicDispatch
class.
You will find a lot of working support code, but the most interesting method is left to you: callMethodFromClassElseFromSuper
.
Go back to the testCode
comment out the call to polymorphismExercise()
You saw the getClass()
method in dynamicallyCallMethodOnObject
, let’s take a closer look at the method.
-
Go to the
main
method in theTestCode
class. Comment out the call topolymorphismExercise
method and comment in the call to thedynamicDispatchExercise
method -
Find the
dynamicDispatchExercise
method in theTestCode
class and complete question 1.
Knowing what the getClass()
method shows us, we will implement code to dynamically dispatch to a given
method based on the runtime type of an object. Java
always performs dynamic dispatch
(also called late binding, or dynamic binding, etc) when invoking a method on an object.
It looks up the runtime type
of the actual object sitting on the JVM
heap and then, if the method has been
overridden one or more times in the inheritance hierarchy, it invokes the most specific method definition.
We want to model this process of dynamic dispatch by implementing a recursive search for the desired method through the inheritance hierarchy.
Use the following strings to print messages and errors while implementing the callMethodFromClassElseFromSuper
method.
String message = String.format("Failed to find a method for %s.%s%s", o.getClass().getName(), method_name, arrayToStringWithParens(arguments));
String.format("Trying to find method [%s] on class [%s]..", method_name, c.getName())
String.format("Found in class %s! Invoking with args %s to produce a %s.\n", c.getName(), Arrays.toString(arguments), m.getReturnType().getName())
String message = String.format("Method %s.%s%s threw:", c.getName(), method_name, arrayToStringWithParens(arguments));
Use the following steps to implement the callMethodFromClassElseFromSuper
method:
-
Since we’ll be using recursion, we need to have a base case. We’ll be recursing up the inheritance hierarchy with
Class.getSuperClass()
. If you do this iteratively we eventually end up with the class Object, which is the parent of all classes inJava
. If you callgetSuperClass()
onObject
, it returnsnull
.-
In your method, first check to see if the
Class
argument isnull
. If it isnull
we know our search failed to find any method to invoke.-
Use an appropriate message from above to return a useful error message.
-
Throw a new
NoSuchMethodException
, giving your error message to the constructor.
-
-
-
Next, call the static method
log
with an appropriate message from above to log a message indicating that you are now trying to find the method on the current class. -
Get the declared methods of the class (using
getDeclaredMethods()
) and loop over them using a for-each loop. -
For each
Method
object, check if its name (returned bygetName()
) is the name of the method you are looking for. -
If it is, further check that its parameter types (returned by
getParameterTypes()
) are compatible with the arguments you are given. Do this with the providedstatic
methodparameterTypesMatchArguments
. -
If the name matches and the argument types are compatible, we’ve found our method!
-
Use the
log
method on an appropriate message from above to state you found a suitable method.
-
-
Try to return the result of invoking the method on the Object o with the provided arguments.
-
Do this by returning the result of
m.invoke(Object o, Object… arguments)
with m being the current method. -
Catch any IllegalAccessExceptions and throw a new RuntimeException, giving the constructor the IllegalAccessException you caught.
-
Catch any InvocationTargetExceptions and log the error use an error message from above. Then throw a new RuntimeException, giving it your message and the InvocationTargetException’s cause (use the
getCause()
method).
-
-
If you looped through all the declared methods on the given class, and none of them matched the desired method, then it’s time to continue the search in the parent class, to see if they have a definition for it. Return the result of recursively calling callMethodFromClassElseFromSuper with the super class of the class argument, and the same parameters otherwise.
Once you have finished implementing and testing the method go to the TestCode
class and complete question 2.
Part Two
Let’s move on to the polymorphismExercise
in the TestCode
class
-
Run the main method and follow the instructions.
-
You will be uncommenting and running the code while working through various questions.
Feel free to use google, talk with other students and ask your TAs questions.
Please show your the TestCode class to your TA and talk about your code and the questions you’ve answered to receive credit