Page 2 of 3
Now that we have examined some of the problem areas with this routine, let's explore ways to address each of those contentious areas.
First off, let's replace the recursion with an explicit while loop that checks for the stopping conditions described earlier. Next, we'll introduce a temporary Frame reference, which will be set inside the loop when we find the the parent Frame object. Note that we set the temporary to our default return value of null. Also notice how the new version of the routine only has a single return statement at the end.
static public Frame GetFrame(Component component)
{
Frame resultingFrame = null;
while (component != null && resultingFrame == null)
{
if (component instanceof Frame) resultingFrame = (Frame)component;
else component = component.getParent();
}
return resultingFrame;
}
Okay, for you byte counters out there, this version does result in three additional bytecode instructions than the original,
recursive version has -- 19 versus 16. However, the new, explicit form never has to worry about running out of stack space
-- the routine is using a single stack variable, resultingFrame, rather than relying on the method invocation stack. This explicit management of the stack data not only results in faster
code in general but is also much more conducive to the optimization efforts of native Java compilers, JIT compilers, and so
on.
The greatest benefit of this new, explicit version is the increased readability, simplicity, and maintainability of the code. So, we have created a version that is safer (no call stack limitations), faster (explicit looping rather than recursion), and clearer about what it's really doing.
We've gone this far in modifying the original, why stop here? Why don't we make the routine more useful too? In other words, why should we settle for a routine that only looks up Frame parents of a Component? Rather than writing a new routine for each type of parent that we may want to look up, let's just make the routine more
generic in what it's searching for!
There are many ways to make this routine more generic. We can make it generic along a number of dimensions including the containment hierarchy and the target parent specification. In this particular case, we are going to limit this routine to sticking to the component container hierarchy but allow the caller to specify the target parent class.
First, here is an example of how you would use the new method to determine a button's parent which is an Applet.
Applet dadApplet = (Applet)GetParent(myButton,"Applet");
In this new version we replace the use of the instanceof operator with a bit of object introspection:
static public Component GetParent(Component component, String compType )
{
Component resultingComponent = null;
while (component != null && resultingComponent == null)
{
if ( compType.equals( component.getClass().getName() ) )
resultingComponent = component;
else component = component.getParent();
}
return resultingComponent;
}
In terms of bytecode instructions, we have introduced one more invoking bytecode because getClass().getName() yields two "invokevirtual" calls -- whereas the statement instanceof has it own special single bytecode. Seems like a pretty reasonable tradeoff given that our routine is now a fair bit more
generic.