反射:如何将一个对象转换为子类而不使用 instanceof?

5

我有一个简单的界面/类:

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

所以,我的问题是,我想将超类对象强制转换为子类对象,而不使用“代码命令”instanceof。

我需要一个正确的命令,就像这样:

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

我该如何获取它?这是可能的吗?

请清理格式!您的代码格式化为代码、块引用和正文。 - Marcelo Cantos
“我希望p.handler(m)调用方法p.handler(m:Message1)”--这不是Java的工作方式!Java是单分派的! - polygenelubricants
顺便说一句,在我的经验中,Java 中的方法重载经常被滥用。容易出现问题,特别是对于类/子类重载而言。只有在需要或增加一些价值时才使用它。有些人没有必要地使用重载,认为这样做很优雅。但事实并非如此。https://dev59.com/LXVC5IYBdhLWcg3wliKe - rsp回答 - leonbloy
2个回答

9

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

现在,即使在主函数中的引用是Message接口类型,它仍然调用Utility::handler(Message1)。


@rsp:在Message中的callHandler方法中添加“abstract”关键字。 - Eyal Schneider
值得一提的是,这种技术通常被称为“多分派”,是“访问者”设计模式背后的基本原理。 - Jules

0

我不确定你的 handle() 方法应该做什么,但是由于它们依赖于 Message 的特定实例,因此你应该考虑在 Message 类中添加 handle() 方法(作为抽象方法)。这样,每个消息都可以实现它自己版本的 handle(),并且你可以享受到多态的好处:

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

这段代码将返回 "Class: Message1",正如您所需。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接