簡體   English   中英

在Java中,我想以“ foo”的名稱調用對象上的方法,但是“ foo”是字符串。 我該如何解決?

[英]In Java, I want to call a method on an object by the name of 'foo', but 'foo' is a string. How do I get around this?

我有一個名為“ foo”的對象(Object foo = new Object())。 我想在另一個方法中調用該對象,在該方法中,我在簽名中傳遞一個帶有該對象名稱的字符串。 如何通過使用代表對象名稱的字符串來調用該對象?

我收到找不到符號錯誤。

這是一些代碼:

//from main method
Object foo = new Object();
Monitor monitor = new Monitor();
//end main method

class Monitor {
  public Monitor() {
    Manager manager = new Manager();
  }


//IMPORTANT - info.objectName is user input, and for this example it is "foo"

  public void processArgument(Instruction info) {
    if (info.command == "read") int value = manager.read(info.objectName);
  }
}

class Manager {
  public int read(String obj) {
    return obj.getRead();
  }
}

class Object {
  private int value;
  public int getRead() {return value;}
}

我希望這是有道理的,雖然我不是很擅長,但是我需要一些幫助。 這是針對具有嚴格的反代碼共享策略的類,因此我嘗試將其盡可能抽象化。

簡短答案

Java或JVM中對此不支持。

長答案為什么

給定MyCustomObject xxx = new MyCustomObject();

在給定String s = "xxx";的情況下,無法實際調用xxx上的任何方法,該方法是對Java中MyCustomObject類型的實例的引用String s = "xxx"; 因為無法在JVM中搜索名為xxx的引用。 沒有一種方法可以讓您在給定String查找參考xxx

重復問題

Java反射:通過輸入名稱來獲取給定類的實例? 如果無法通過引用名稱找到它,則無法在其上調用任何方法!

Hacky解決方法

您可以自己將該引用存儲在某種Map<String, T>結構中,然后在周圍傳遞該結構並自己進行搜索,但這並不是JVM或語言本身所內置的。 強制執行此操作幾乎是不可能的,它會導致與某些static數據的緊密耦合,而其他許多不良的設計問題也將導致很多麻煩。

如果要調用名稱為“ foo”的方法,

  1. 獲取類對象的foo方法。
  2. 調用getDeclaredMethod(),該方法返回Method對象。
  3. 在方法對象上調用invoke方法。

Class classOfFoo = FooClass.class;

FooClass obj = new FooClass(); //Or may be you have your own object.

classOfFoo.getDeclaredMethod("foo",fooParameter.class).invoke(obj,fooParametersObj);

您可能想看看反射API。

getDeclaredMethod(字符串名稱,類... parameterTypes)

公共對象invoke(Object obj,Object ... args)

有兩種本機執行此操作的方法,另一種是本機執行的方法。

  • 如果陳述
  • 函子圖
  • 反射

選項1

您擁有的是選項1,而且大多數情況下都是正確的,只是使用了錯誤的比較方式。 比較你的

public void processArgument(Instruction info) {
    // this is bad - uses reference comparison
    if (info.command == "read") 
        int value = manager.read(info.objectName);
}

與推薦

public void processArgument(Instruction info) {
    // this is good - actually compares the values
    if (info.command.equals("read"))
        int value = manager.read(info.objectName);
}

有些人認為這樣做更好,因為如果info.command為null,則不會引發異常。 我個人不喜歡這樣,因為我寧願得到例外,但是許多人主張這樣做,而且他們有完全正當的理由。

public void processArgument(Instruction info) {
    // "read" can never be null, so no null pointer exception here
    if ("read".equals(info) )
        int value = manager.read(info.objectName);
}

當然,隨着您添加更多行為,您只需添加更多if語句。

在Java 7中,您可以執行以下操作:

public void processArgument(Instruction info) {
    switch(info.command) {
        case "read": manager.read(info.objectName); break;
        case "write": manager.write(info.objectName); break;
        default: throw new IllegalArgumentException("Command " + info.command + " not supported");
    }
}

選項2

另一種選擇是使用利用匿名類的Map,如下所示:

// define this somewhere
abstract class Functor {
    Manager m;
    Functor(Manager m) { this.m = m; }
    void execute(Instruction info);
}

// somewhere you have access to
Map<String,Functor> funcs = new HashMap<String,Functor>();

// add this to a static block, or constructor, depending
funcs.put("read", new Functor(manager) {
    public void execute(Instruction info) { m.read(info.objectName); }
});
funcs.put("write", new Functor(manager) {
    public void execute(Instruction info) { m.write(info.objectName); }
}

然后當你打電話給你的論點時

public void processArgument(Instruction info) {
    Functor f = funcs.get(info.command);
    if(f == null) throw new IllegalArgumentException("Operation " + info.command + " not supported");
    f.execute(info);
}

選項3

像薩加爾·達巴斯(SagarDabas)在他的帖子中概述的那樣,使用反思。 請注意,這可能需要特殊的訪問權限,並且不會為您提供更靈活的正確性選項。

暫無
暫無

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

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