簡體   English   中英

如何正確使用Class.cast()?

[英]How to use Class.cast() properly?

我有一個如下所示的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(命令命令)。 它接受命令param,檢查commandName字段,並使用該名稱將命令強制轉換為Command的子類,負責實現命令邏輯。 在此示例中,您可能擁有一個CommandName,其commandName為“authenticate”,而command和pw存儲在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類嗎?

UPDATE

更多背景。 Server類處理的不僅僅是AuthenticateCommands。 可以有任意數量的Command子類,具體取決於項目。 我試圖讓編寫客戶端的人簡單地傳遞一個只帶有名稱和參數的序列化Command對象。 我可以強制客戶端“了解”AuthenticateCommand和所有其他的,然后序列化它們並傳遞它們,但這似乎是次優的,因為子類之間的唯一區別是executeCommand的實現,客戶端並不關心或了解。 所以我只想要一種方法讓客戶端傳遞父類,並使用該父類中的數據將其強制轉換為適當的子類。

我想我可以使用newInstance()代替cast而只是創建一個新對象,但這看起來很浪費。 我想我也可以廢除處理邏輯的子類的概念並將它們移動到方法中,然后processCommand將調用適當的方法。 不過,這對我來說也很不舒服。

你為什么要施展? 你只是試圖調用executeCommand ,這在Command上可用...所以只需寫:

command.executeCommand();

哪個應該編譯運行。 目前還不清楚地圖的位置。

至於為什么演員表失敗...我的猜測是該命令的ClassLoader不是此時的默認ClassLoader,因此implementorClass是同一個類,但由不同的ClassLoader加載...這使得它成為一個類關於JVM的差異類。

編輯:我會說你的設計壞了。 您正在傳遞的Command對象未正確履行其角色。 一種選擇是擁有一個知道名稱的新RemoteCommand子類,並且當調用其executeCommand方法時,它會構建適當的子類實例。 是的,它需要建立一個類的實例。 如果沒有該類的實例,則無法在類上調用實例方法,並且不能使一個對象“假裝”它實際上是不同類型的對象。 如果AuthenticationCommand有一些額外的字段試圖使用怎么辦? 這些價值來自哪里?

一個更好的選擇是讓你的序列化/反序列化層執行此操作,這樣當你到達這段代碼時,你已經有了一個AuthenticationCommand - 你可以使用這個答案頂部的代碼。

你真的需要實例化它。 您只能通過強制轉換將“ Class<T> ”轉換為具體實例。 此外,與您的代碼段相反,應該以相反的方式完成轉換。

Class<?> implementorClass = Class.forName(implementorClassString);
Command instance = Command.class.cast(implementorClass.newInstance());
instance.executeCommand();

更不用說這一切都是一種設計氣味。

只有當Command Object在運行時實際引用Authenticate Command實例時,才能進行向下轉換。 這是多態論所說的不是嗎?

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM