tags:

views:

408

answers:

6

Hi all,

I have

interface FooI
class FooA implements FooI
class FooB implements FooI
class FooC implements FooI

I wrote a class "Handler" that has the following methods

static double handle(FooA f)
static double handle(FooB f)
static double handle(FooI f)

and I have a function like the following:

void caller(FooI f)
{
    Handler.handle(f);
}

with f just being known as a class implementing FooI. However f is an instance of FooA

Instead of calling the method for FooA, the method for FooI is called.

When I use f.getClass().getName() I get the correct class name (FooA).

I am confused because I expected the best-suited method to get called, namely the one for FooA.

I wanted to use the FooI method as a fallback to handle classes that could be implemented later, and I also want to handle f without having one big function where I am doing instanceof checks for all currently known classes implementing my interface.

What would be a good approach to do this?

+1  A: 

I don't know exactly what your design is, but might the 'handle' functionality be better placed in your concrete FooI implementations?

teabot
Thanks teabot, that's how I implemented the whole thing in the end :-).
Kage
+16  A: 

Overload resolution is done at compile time rather than execution time in Java. The signature was picked based on the compile-time type of your variable. Only overrides are determined at execution time.

A common solution for this in languages like Java is to use double dispatch and the visitor pattern.

Personally I'm not a huge fan of this. I prefer to try to design my way around it. That's not always possible, of course, but it's worth at least attempting.

Jon Skeet
Just by curiosity...why don't you like these patterns ?
LB
Thanks a bunch Jon! I totally forgot about the whole resolution issue.
Kage
@LB I can't vouch for Jon, but I personally find them to be rather ugly because now there's a bunch of indirection and boilerplate in front of what is, conceptually, a very straightforward operation.
Hank Gay
It's amazing how often this question is asked and answered. I bet there have been at least a couple of hundred points in reputation score attributed to this question. I only got 10 of em :-(
Robin
A: 

you should not use a static method for that, static methods obey to other rules than non final instance methods

dfa
The static-ness is irrelevant here. The point is that it's *overload* resolution which is taking place, not *override* resolution.
Jon Skeet
A: 

You could transform your interface into an abstract class, with a handler implementation. Then you implement it, and FooA and FooB overrides it

Samuel Carrijo
+3  A: 

You expect that the JVM seaches for the best fitting method at run time but that doesn't happen, actually. Instead the method to call is selected during compile time, when the only known information is that f is a class that implements FooI.

The best approach for that problem, the one that avoids the instanceof checks, might be moving the "handle" method into those classes FooA, FooB, FooI.

ammoQ
Thanks ammoQ! I totally forgot about that :-(.
Kage
+1  A: 

Java resolves which method to call at compile time using the reference type, which in your example is FooI - if you think about it this makes sense as the reference type is all it really has to go on at compile time.

Your Handler class doesn't handle(FooI f) and so as far as the compiler is concerned there is no valid handle method to call.

Nick Holt