1

我有一个名为“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;}
}

我希望这是有道理的,我不太擅长这个,但我需要一些帮助。这是针对具有严格的反代码共享策略的类,所以我试图尽可能抽象。

4

3 回答 3

0

简短的回答

Java 或 JVM 不支持此功能。

长答案为什么

给定MyCustomObject xxx = new MyCustomObject();

xxxMyCustomObjectString s = "xxx";. 因为无法在 JVM 中搜索名为xxx. 没有任何方法可以让您查找xxx给定任意String.

重复的问题

Java反射:通过输入名称获取给定类的实例?如果你不能通过引用名找到它,你就不能在它上面调用任何方法!

哈克解决方法

您可以自己将此引用存储在某种Map<String, T>结构中,然后传递该结构并自行搜索,但这不是 JVM 或语言本身内置的任何东西。强制执行这一点几乎是不可能的,它会给某些static数据引入紧密耦合,并且许多其他糟糕的设计问题会在未来引起很多麻烦。

于 2012-07-17T04:16:24.093 回答
0

如果你想调用一个名为“foo”的方法,

  1. 获取 foo 方法的类对象。
  2. 调用 getDeclaredMethod(),它返回 Method 对象。
  3. 调用方法对象上的调用方法。

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(String name,Class... parameterTypes)

公共对象调用(对象 obj,对象... args)

于 2012-07-17T04:58:00.250 回答
0

有两种方法可以原生地做到这一点,还有一种不那么原生的方式。

  • 如果语句
  • 函子图
  • 反射

选项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 在他的帖子中概述的内容。请注意,这可能需要特殊的访问权限,并且不会为您提供灵活的正确性选项。

于 2012-07-17T17:19:50.037 回答