1

I have an object named "foo" (Object foo = new Object()). I want to call this object in another method where I pass a string with this object name in the signature. How can I call this object by using a string that represents the name of the object?

I am getting a cannot find symbol error.

Here is some code:

//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;}
}

I hope that makes sense, I'm not very good at this but I need some help. This is for a class with a strict anti-code-sharing policy so I tried to make this as abstract as I could.

fareed
  • 3,034
  • 6
  • 37
  • 65
Archer
  • 111
  • 3
  • 10
  • 6
    Uh, "what"? Please show code .. –  Jul 17 '12 at 04:09
  • In what context (scope) was foo defined? How is that scope related to the context where you want to call it using the string "foo". – walrii Jul 17 '12 at 04:14
  • It can't be done. Sounds like you need a `Map`, though without seeing the use case it's hard to know if there's a better option. – yshavit Jul 17 '12 at 04:16
  • @pst in some languages (but not Java, at least directly) you can do things like $foo = new Object(); $name = "foo"; $$name->method(); If OP is used to scripting languages, this makes sense. – walrii Jul 17 '12 at 04:19
  • @yshavit If foo is a class member, then reflection can be used if the instance is known or if it is a static member. – walrii Jul 17 '12 at 04:21
  • True -- I was assuming (and OP's edit confirms) that the question was about local vars n – yshavit Jul 17 '12 at 04:23
  • @yshavit given the new info, you are indeed correct :) – walrii Jul 17 '12 at 04:27

3 Answers3

0

Short answer

There is no support for this in Java or the JVM.

Long Answer Why

Given MyCustomObject xxx = new MyCustomObject();

There is no way to actually call any methods on xxx which is a reference to an instance of a type of MyCustomObject in Java given the String s = "xxx";. Because there is no way to search the JVM for the reference named xxx. There is no method that allows you to look up the reference xxx given an arbitrary String.

Duplicate Question

Java Reflection: get instances of a given class found by entering its name? If you can't find it by reference name, you can't call any methods on it!

Hacky Workaround

You could store this reference in some kind of Map<String, T> structure yourself and then pass that structure around and search it yourself, but that isn't anything that would be built into the JVM or the language itself. It would be next to impossible to enforce this, it would introduce tight coupling to some static data, and lots of other bad design things would cause lots of headaches down the road.

Community
  • 1
  • 1
0

If you want to call a method with name "foo",

  1. get the class object which foo method.
  2. Call the getDeclaredMethod(), which return Method object.
  3. Call the invoke the method on thw Method object.

Class classOfFoo = FooClass.class;

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

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

You may want to have a look on reflection API.

getDeclaredMethod(String name,Class... parameterTypes)

public Object invoke(Object obj, Object... args)

SagarDabas
  • 89
  • 1
  • 2
  • 9
0

There's two ways to natively do this, and one less native way.

  • If statements
  • Functor map
  • Reflection

Option 1

What you have is option 1, and it's mostly correct, you just are using the wrong way of comparison. Compare yours

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

with the recommended

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

Some would consider it even better to do the following because if info.command is null this will not throw an exception. Personally I don't like that because I'd rather get the exception, but many people advocate it, and they have a perfectly valid reason for doing it.

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);
}

Of course, as you add more behaviours, you just add more if statements.

In Java 7, you can do this:

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");
    }
}

Option 2

Another option is to use a Map utilizing anonymous classes, like so:

// 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); }
}

Then when you call your arguments

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);
}

Option 3

Use reflection as SagarDabas outlines in his post. Note that this may require special access permissions, and is not going to give you as flexible of correctness options.

corsiKa
  • 81,495
  • 25
  • 153
  • 204