我有一个如下所示的 Command 类:
public class Command {
...
private String commandName;
private Object[] commandArgs;
...
public void executeCommand() {}
}
我还有一个 Command 的子类,AuthenticateCommand:
public class AuthenticateCommand extends Command {
...
@Override
public void executeCommand() {
...
}
}
现在想象一个类 Server,它有一个方法 processCommand(Command command)。它接受命令参数,检查 commandName 字段,并使用该名称将命令转换为负责实现命令逻辑的 Command 子类。在此示例中,您可能有一个命令,其 commandName 为“authenticate”,用户名和密码存储在 commandArgs 数组中。 processCommand() 会将 Command 转换为 AutheticateCommand 并调用executeCommand() 方法。我试图通过以下方法来完成此任务(commandMap 只是一个将 commandName 映射到其实现类名称的 Map):
public void processCommand(Command command) {
String commandName = command.getCommandName();
String implementorClassString = commandMap.get(commandName);
try {
Class implementorClass = Class.forName(implementorClassString);
Object implementor = implementorClass.cast(command);
Method method = implementorClass.getDeclaredMethod("executeCommand", null);
method.invoke(implementor);
} catch (ClassNotFoundException e) {
logger.error("Could not find implementor class: " + implementorClassString, e);
} catch (NoSuchMethodException e) {
logger.error("Could not find executeCommand method on implementor class: " + implementorClassString, e);
} catch (IllegalAccessException e) {
logger.error("Could not access private member/method on implementor class: " + implementorClassString, e);
} catch (InvocationTargetException e) {
logger.error("Could not invoke executeCommand method on implementor class: " + implementorClassString, e);
}
}
对implementorClass.cast()的调用抛出ClassCastException。难道它不应该能够以这种方式向下转换为 AuthenticateCommand 类吗?
更新
更多背景信息。 Server 类不仅仅处理 AuthenticateCommands。根据项目的不同,可以有任意数量的 Command 子类。我试图让编写客户端的人能够简单地传递仅包含名称和参数的序列化命令对象。我可以强制客户端“了解”AuthenticateCommand 和所有其他命令,然后序列化它们并传递它们,但这似乎不是最佳选择,因为子类之间的唯一区别是执行命令的实现,而客户端并不关心或知道有关。所以我只是想要一种方法让客户端传递父类,并使用该父类中的数据将其转换为适当的子类。
我想我可以使用 newInstance() 而不是强制转换并创建一个新对象,但这似乎很浪费。我想我也可以取消处理逻辑的子类的概念并将其移至方法中,然后 processCommand 将调用适当的方法。不过,这对我来说也感觉很糟糕。
最佳答案
你为什么要选角?您只是想调用 executeCommand
,并且可以在 Command 上使用...所以只需编写:
command.executeCommand();
它应该编译并运行。根本不清楚 map 的来源。
至于为什么转换失败...我的猜测是该命令的类加载器此时不是默认的类加载器,因此 implementorClass
是相同的类,但由不同的 ClassLoader 加载...这使得它对于 JVM 而言是一个不同的类。
编辑:我想说你的设计被破坏了。您传递的 Command
对象没有正确履行其职责。一种选择是拥有一个知道名称的新 RemoteCommand
子类,并且当调用其 executeCommand
方法时,它会构建适当的子类实例。是的,它将需要构建该类的实例。如果没有该类的实例,则无法调用该类的实例方法,并且无法使一个对象“假装”它实际上是不同类型的对象。如果 AuthenticationCommand 有一些尝试使用的额外字段怎么办?值从哪里来?
更好的选择是让您的序列化/反序列化层执行此操作,这样当您到达这段代码时,您已经得到一个AuthenticationCommand
- 您可以使用此答案顶部的代码。
关于java - 如何正确使用Class.cast()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/3723897/