5

I have this simple interface/class:

public abstract class Message {}

public class Message1 extends Message {}

public class Message2 extends Message {}

And an utility class:

public class Utility {
    public void handler(Message m) {
        System.out.println("Interface: Message");
    }

    public void handler(Message1 m) {
        System.out.println("Class: Message1");
    }

    public void handler(Message2 m) {
        System.out.println("Class: Message2");
    }
}

Now, the main class:

public static void main(String[] args) {

    Utility p = new Utility();

    Message1 m1 = new Message1();
    p.handler(m1);

    Message m = (Message) m1;
    p.handler(m);

}

The output is

> Class: Message1
> Interface: Message

I would that p.handler(m) call the method p.handler(m:Message1)

I don't want use the "manual" command instanceof because I have many cases:

if(m instance of Message1)
p.handler((Message1)m)
else if (m instanceof Message2)
p.handler((Message2)m)
...

If I call m.getClass() I obtain "mypackage.Message1", so the subclass and not the superclass.

I try with this code (use reflection):

p.handler(m.getClass().cast(m));

But the output is

> Interface: Message

So, this is my problem. I would do a runtime cast of superclass object to subclassobject without use the "code command" istanceof.

I would a right command like this:

p.handler((m.getclass)m);

How can I obtain it? It's possible?

Matt Ball
  • 354,903
  • 100
  • 647
  • 710
jfabrizio
  • 760
  • 7
  • 15
  • Please clean up the formatting! You have code formatted as code, block-quotes and body-text. – Marcelo Cantos May 06 '10 at 10:41
  • "I would like that p.handler(m) call the method p.handler(m:Message1)" -- That's not how Java works! Java is single-dispatch! – polygenelubricants May 06 '10 at 11:11
  • anwered by rsp - BTW, in my experience, method overloading is frequently abused in Java. Prone to problems, specially for classes/subclasses overloading as here. Use it only if needed or adds some value. Some people use overloading without need, thinking it's somehow elegant. It's not. http://stackoverflow.com/questions/248222/method-overloading-can-you-overuse-it – leonbloy May 06 '10 at 12:02

2 Answers2

9

Java will call the method on the basis of information known at compile time. What you could do is add a method to the interface that calls the correct handler method for the object.

public abstract class Message {

    public abstract void callHandler(Utility utility);

}

public class Message1 extends Message{

    public void callHandler(Utility utility) {
        utility.handler(this);
    }
}

Your calls to the handler become:

Message m=(Message) m1;
m.callHandler(p);

which now calls Utility::handler(Message1) even though the reference in main is of type of the Message interface.

Timo
  • 2,212
  • 2
  • 25
  • 46
rsp
  • 23,135
  • 6
  • 55
  • 69
  • @rsp: add the 'abstract' keyword to the callHandler method in Message. – Eyal Schneider May 06 '10 at 11:09
  • It is perhaps worth pointing out that this technique is generally known as "multiple dispatch" and is the basic principle behind the "Visitor" design pattern. – Jules May 16 '14 at 06:27
0

I am not sure what your handle(..) methods are supposed to do, but since they depend on the specific instance of Message, you should consider adding handle() method to your Message class (as abstract method). This way, each message implements its version of handle, and you can enjoy the benefits of polymorphism:

Message m = new Message1();
m.handle();

This code will return "Class: Message1", as you need.

Eyal Schneider
  • 22,166
  • 5
  • 47
  • 78