Casting Proxies – 获取ClassCastException

当我将动态代理类转换为我想要的对象时,我会有些奇怪。 在运行时,在某些条件下,我收到ClassCastException。

为了更好地解释这一点,这里是我想要使用的类/接口的定义。 括号已被放置在(应该)不相关的任何扩展接口上。

public interface CommandSender (extends Permissible) public interface ConsoleCommandSender extends CommandSender, (Conversable) public interface Player extends (HumanEntity, Conversable), CommandSender, (OfflinePlayer, PluginMessageRecipient) 

完整的Javadoc可以在这里找到: http : //jd.bukkit.org/apidocs/org/bukkit/command/CommandSender.html

现在,这是我的代理类的代码:

 public class CommandSignsMessagingProxy implements InvocationHandler { private Object sender; private Object receiver; private boolean silent; public static Object newInstance(Object proxy) { return newInstance(proxy, proxy, false); } public static Object newInstance(Object proxy, boolean silent) { return newInstance(proxy, proxy, silent); } public static Object newInstance(Object sender, Object receiver) { return newInstance(sender, receiver, false); } public static Object newInstance(Object sender, Object receiver, boolean silent) { return Proxy.newProxyInstance( sender.getClass().getClassLoader(), sender.getClass().getInterfaces(), new CommandSignsMessagingProxy(sender, receiver, silent)); } private CommandSignsMessagingProxy(Object sender, Object receiver, boolean silent) { this.sender = sender; this.receiver = receiver; this.silent = silent; } // Is called whenever a method is invoked public Object invoke(Object p, Method m, Object[] args) throws Throwable { Object result = null; try { String name = m.getName(); // If the receiver is being sent a message, only do so if the silent flag is not set if (name == "sendMessage" || name == "sendRawMessage") { if (!silent && receiver != null) result = m.invoke(receiver, args); } else { result = m.invoke(sender, args); } } catch (InvocationTargetException e) { throw e.getTargetException(); } catch (Exception e) { throw new RuntimeException("Unexpected invocation exception: " + e.getMessage()); } return result; } } 

这是一个完全可用的类实例:

 Player proxy = (Player)CommandSignsMessagingProxy.newInstance(player, false); proxy.sendMessage("Hi! Silent is turned off, so you can see this!"); proxy.setOp(true); proxy.other_stuff(); 

然而,这个不起作用:

 ConsoleCommandSender ccs = plugin.getServer().getConsoleSender(); CommandSender cs = (CommandSender)CommandSignsMessagingProxy.newInstance(ccs, false); 

在运行时,此示例将生成以下内容:

 java.lang.ClassCastException: $Proxy18 cannot be cast to org.bukkit.command.CommandSender 

创建的代理类需要传递它想要实现的接口,

 return Proxy.newProxyInstance( sender.getClass().getClassLoader(), sender.getClass().getInterfaces(), new CommandSignsMessagingProxy(sender, receiver, silent)); 

失败似乎发生,因为可能无法从调用sender.getClass()。getInterfaces()方法返回CommandSender接口。 因此,尝试通过调试来确定它是否正确通过。 如果没有尝试手动将接口发送到该方法,看看它是否有效。