Отражение: приведение объекта к подклассу без использования instanceof - PullRequest
4 голосов
/ 06 мая 2010

У меня есть этот простой интерфейс / класс:

public abstract class Message {}

public class Message1 extends Message {}

public class Message2 extends Message {}

И служебный класс:

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");
    }
}

Теперь основной класс:

public static void main(String[] args) {

    Utility p = new Utility();

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

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

}

Выход

> Class: Message1
> Interface: Message

Я бы p.handler(m) вызвал бы метод p.handler(m:Message1)

Я не хочу использовать «ручную» команду instanceof, потому что у меня много дел:

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

Если я позвоню m.getClass(), я получу «mypackage.Message1», поэтому подкласс, а не суперкласс.

Я пытаюсь с этим кодом (использовать отражение):

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

Но на выходе получается

> Interface: Message

Итак, это моя проблема. Я бы выполнил приведение объекта суперкласса во время выполнения к подклассу объекта без использования istanceof "code command".

Я бы выбрал правильную команду:

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

Как мне его получить? Это возможно?

Ответы [ 2 ]

8 голосов
/ 06 мая 2010

Java будет вызывать метод на основе информации, известной во время компиляции. Что вы можете сделать, это добавить метод в интерфейс, который вызывает правильный метод-обработчик для объекта.

public abstract class Message {

    public abstract void callHandler(Utility utility);

}

public class Message1 extends Message{

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

Ваши звонки обработчику становятся:

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

, который теперь вызывает Utility :: handler (Message1), хотя ссылка в main имеет тип интерфейса Message.

0 голосов
/ 06 мая 2010

Я не уверен, что должны делать ваши методы handle (..), но, поскольку они зависят от конкретного экземпляра Message, вам следует рассмотреть возможность добавления метода handle () в ваш класс Message (как абстрактный метод). Таким образом, каждое сообщение реализует свою версию дескриптора, и вы можете воспользоваться преимуществами полиморфизма:

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

Этот код будет возвращать "Class: Message1", как вам нужно.

...