aspose file tools*
The moose likes Java in General and the fly likes Polymorphism and Method Signatures Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Java » Java in General
Bookmark "Polymorphism and Method Signatures" Watch "Polymorphism and Method Signatures" New topic
Author

Polymorphism and Method Signatures

Timothy Frey
Ranch Hand

Joined: Jul 22, 2006
Posts: 56
I'm having a problem understand exactly what's going on inside the JRE with the following circumstances. Let's say, for example, I have the following 2 classes that represent Actions:


Additionally, SpecificObject extends GenericObject. Now, when I execute this code fragment:



The output is, as expected:
Generic invoke method!
Specific invoke method!

However, if I change the reference type of action to the supertype:



The output is:
Generic invoke method!
Generic invoke method!

What's going on here? I thought that the method binding depended on the actual object type and not the reference type. However, if I refer to my SpecificAction object by a GenericAction method, the invoke method called is always the one that accepts a GenericObject, even if that object is actually a subclass of GenericObject. If I had to guess I would say that the JRE finds a suitable match in the reference type class and realize there is an even better match in one of the subclasses.

To give you some background on what I'm working on, I'm playing around with a command line parser (say, for a text adventure game) and I'm trying to make it as extensible as possible. All game objects extend from a certain base class; the same goes for game actions. I ran into this problem when I was trying to do this:

GameAction action = new DoorAction();
action.invoke(new Door());

The DoorAction class has an "invoke" method that takes a Door parameter. However, GameAction, from which DoorAction extends, has an "invoke" method that takes a general GameObject. The above code should "open the door" but instead it just prints a message, which is what GameAction is designed to do. If I change the reference type from GameActin to DoorAction everything works correctly.

Can anyone shed some light as to what's going on here?
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24184
    
  34

Hi,

First, although I understand what you're asking, your example code is wrong in that under no circumstances could it produce the output shown. I don't think you want the "GenericAction" class to exist; you mean that both "invoke()" methods should be in one class, like



Given this code, then you'd see the behavior you described.

Now: what's going on? This is not polymorphism. Polymorphism is when there are multiple versions of a method in different classes with identical signatures; in particular, there's a version in a superclass and a version in a subclass. Under these circumstances, the JVM will look up which method to call at runtime using the actual class of the object you invoke the method on:



That's not what's going on in your example. There, you have only one class, and it contains several methods by the same name with different signatures -- i.e., different argument lists. This is called method overloading, and it's really little more than a convenience. It's not much really different from giving the multiple methods different names. They're separate methods, and at runtime, the JVM knows specifically which one to invoke -- it's not dynamic at all.

In this case, the compiler decides which method signature to invoke based on the compile-time type of the arguments. So invoke(SpecificObject) is called when you pass a variable of type SpecificObject to SpecificAction.invoke(), and invoke(GenericObject) is called when you pass a variable of type GenericObject, even if this latter variable points to a SpecificObject.


[Jess in Action][AskingGoodQuestions]
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
I suspect that SpecificAction extended GenericAction and the OP mistakenly thought they were overridding the method.
Timothy Frey
Ranch Hand

Joined: Jul 22, 2006
Posts: 56
Whoops, you're right, SpecificAction does extend GenericAction. I know that I'm not overriding in this example, that's the point. The "workaround" I have right now is to override the method inherited from Generic Action:



I know it's not overriding, it's closer to overloading but even that might not be the correct term. For example, if these two methods were declared in the same class:

public void invoke(GenericObject obj){}
public void invoke(SpecificObject ojb){}

That would be overloading, right? In this case, if I run a simple test and call invoke with both a GenericObject and a SpecificObject everything works as expected. However, what I'm doing is basically splitting up these 2 methods, putting 1 in the base class and 1 in the child class. Now, things start to get weird. If I call invoke() and pass in a SpecificObject, the method for GenericObject is called.

Again, this depends on the reference type of the object I'm calling invoke on. If the reference type is of SpecificAction everything works fine. Presumably because, to the JVM, it looks like both of these methods are in the same class again and it has no trouble picking the one for SpecificObject. If the reference type is of GenericAction, the JVM seems to call the first method that matches the signature and doesn't look in the subclass.

Am I making any sense? Thanks for the quick replies, by the way, I really appreciate them!
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
It's still overloading. Your method in SpecificAction overloads the method inherited from GenericAction. The method invoked is determined at compile-time as Ernest described.
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Note that the JVM has absolutely nothing to do with this. The method with the most specific signature (perhaps poor wording on my part) is the method the compiler will choose. In other words, if you're passing a String and there's one method that accepts an Object and another that accepts a String it will always choose the method that accepts the String even though it could be either. If you alter your code to pass an Object, regardless of whether or not that Object happens to actually be a String, it will choose the method that accepts an Object. It is not decided at runtime.
Timothy Frey
Ranch Hand

Joined: Jul 22, 2006
Posts: 56
Ahhhhhh, now I see what's going on. Thanks for clearing that up. I'm not a stranger to polymorphism but I was trying to get fancy in this particular project. If I remove the parameter from the invoke() method everything works like I want it to. Is there any way I can make this work without casting the GenericObject down into its actual type? My original idea was to provide the one invoke method that took the specific object I was looking for so I could do something special. The invoke method that these SpecificActions inherited would talk care of everything except for the special cases. Obviously this didn't work.
Ernest Friedman-Hill
author and iconoclast
Marshal

Joined: Jul 08, 2003
Posts: 24184
    
  34

I believe you are struggling to invent the Visitor design pattern. Basically what visitor allows you to do is dynamically dispatch overloaded method calls based on the argument type -- i.e., it looks like runtime overload resolution. It looks something like this:

Timothy Frey
Ranch Hand

Joined: Jul 22, 2006
Posts: 56
I'm still struggling here. I took a look at your example and the Wikipedia page(s) but I don't know if that's what I want. Basically what I'm trying to achieve is the ability for someone (probably me, could be anyone) to be able to define new types of objects and actions without having to modify any interfaces or base classes.

In your example, what happens if we introduce Class D? Wouldn't we have to change the Visitor interface? Additionally, my Action doesn't need to know about all objects that extend from GenericObject, only a small subset.

The thing that's giving me problems is the coupling between the Actions and the Objects. The Objects contain a set of Actions that can be invoked. However, when invoking these actions I need to pass in a reference to the invoker (the Object) because the Action often modifies the Object. This reference doesn't do me any good if its of the GenericObject type; it needs to be of the actual type.

Now that I understand that method overloading is resolved at compile time, this is what I think I need. Each Object keeps a collection of Actions. When I retrieve the appropriate action, before invoking it, I need to cast it back to its actual type. Once I do that, I need to cast the reference to the object that's doing the invoking from GenericObject to it's actual type. I can get this to work by hardcoding the casts. I tried using reflection to do this automatically but failed miserably.

Thanks again for putting up with me. I'm sure there is a simple solution that everyone uses for this type of problem that I'm just not seeing.
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
I've bumped into exactly the same situation. Google for Double Dispatch. It's a way to call a generic method on an object that calls an overloadable method passing itself. That gives the specific type to the overloaded method. Visitor is a rather indirect example; you may find other examples closer to what you need.


A good question is never answered. It is not a bolt to be tightened into place but a seed to be planted and to bear more seed toward the hope of greening the landscape of the idea. John Ciardi
Ken Blair
Ranch Hand

Joined: Jul 15, 2003
Posts: 1078
Based upon your description I would think you were getting pretty close to as good of a solution as you can expect. If I've got this right you have a GenericAction that is passed a GenericObject. When a SpecificObject happens to be passed to a SpecificAction you want some specific implementation to take place instead? Visitor and double dispatch almost seem overly complex. I don't see why you don't just use polymorphism and check for that specific type in the subclass's implementation. e.x.



Of course, your needs might not be quite so simplistic.
Stan James
(instanceof Sidekick)
Ranch Hand

Joined: Jan 29, 2003
Posts: 8791
You may (or may not) be able to turn the design around a bit. Rather than try to make one action with overloaded methods, make an action per SpecificObject, ala Command or Strategy patterns. I had to add polymorphic behavior to DTO parameters and wound up with something like:

The factory can map to the parameter classname or a field on the parameter or whatever to look up an action classname or instance. The factory is initialized from configuration so we can add more parameter/action pairs without touching the code.

BTW: I'm less than comfortable with a family of actions that you seem to be trying for: Z extends Y ... D extends C extends B extends A and each just adds one overloaded method.

Another random brain cell firing ... maybe 20 years ago PJ Plauger wrote about imagining a diagram of a system - all those boxes and lines and arrows - then picking it up by some box in the middle of the mess and shaking it until a new shape emerged with a new center. The Strategy idea is not what you asked for, but see what happens when you shake your class diagram around a while. I hope it's a nice macrame plant hanger (showing my age again) not a rat's nest.
[ September 08, 2006: Message edited by: Stan James ]
Timothy Frey
Ranch Hand

Joined: Jul 22, 2006
Posts: 56
Ken, that's exactly the "solution" that I came up with. It's a little messy but it works.

On the other hand, after going over this with a few people, and thanks in no small part to the advice in this thread, I think this whole design is a huge mess and not worth the trouble. I've been thinking about the types of objects and actions one would need to make a Zork-ish type of game and, basically, they are all pretty much the same. Why do I need a seperate class for doors and objects? Why do I need a separate action for opening doors and pulling levers? The answer is, of course, that I don't.

I think in the end I'm going to end up with only the GenericObject type of class. Inside I'll add a properties list that can hold whatever state information this particular object needs. I'll do something similar with the Action classes; they will pretty much always just change the values of some object's properties.

Thanks again, guys.
 
Consider Paul's rocket mass heater.
 
subject: Polymorphism and Method Signatures