22

Example code:

int width = 5;
int area = 8;
int potato = 2;
int stackOverflow = -4;

Now, say I want to have the user input a string:

String input = new Scanner(System.in).nextLine();

Then, say the user inputs potato. How would I retrieve the variable named potato and do stuff with it? Something like this:

System.getVariable(input); //which will be 2
System.getVariable("stackOverflow"); //should be -4

I looked up some things and did not find much; I did find a reference to something called "the Reflection API," but that seems too complicated for this one simple task.

Is there a way to do this, and if so, what is it? If "Reflection" does indeed work and if it is the only way, then how would I use it to do this? The tutorial page for it has all sorts of internal stuff that I can't make any sense of.

EDIT: I need to keep the Strings in the variables for what I am doing. (I can't use a Map)

6
  • 2
    You would need to use reflection. Commented Nov 8, 2012 at 22:19
  • 2
    No, you'd want to use a Map from strings to ints. Reflection is overkill for this task. Commented Nov 8, 2012 at 22:20
  • Alright, how would I do that? The reflection tutorial page is all complicated and weird and blah. Commented Nov 8, 2012 at 22:20
  • 2
    You might want to add your values to a dictionary. So you get a key pair value. Commented Nov 8, 2012 at 22:20
  • 1
    I don't think this is possible via reflection for method variables, only class attributes... Commented Nov 8, 2012 at 22:21

6 Answers 6

18

Using reflection doesn't seem like a good design for what you're doing here. It would be better to use a Map<String, Integer> for example:

static final Map<String, Integer> VALUES_BY_NAME;
static {
    final Map<String, Integer> valuesByName = new HashMap<>();
    valuesByName.put("width", 5);
    valuesByName.put("potato", 2);
    VALUES_BY_NAME = Collections.unmodifiableMap(valuesByName);
}

Or with Guava:

static final ImmutableMap<String, Integer> VALUES_BY_NAME = ImmutableMap.of(
    "width", 5,
    "potato", 2
);

Or with an enum:

enum NameValuePair {

    WIDTH("width", 5),
    POTATO("potato", 2);

    private final String name;
    private final int value;

    private NameValuePair(final String name, final int value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public String getValue() {
        return value;
    }

    static NameValuePair getByName(final String name) {
        for (final NameValuePair nvp : values()) {
            if (nvp.getName().equals(name)) {
                return nvp;
            }
        }
        throw new IllegalArgumentException("Invalid name: " + name);
    }
}
Sign up to request clarification or add additional context in comments.

1 Comment

I need to keep the Strings in the variable for what I am doing.
4

Variable names are only available at compiler time. Reflection only gives access to class declarations and items declared inside them, but not to local variables. I suspect that a Map of some kind will be a more appropriate solution to your real problem. Specifically, check out HashMap and TreeMap.

Comments

3

Instead of trying to find the value of a variable name, why don't you use a Map with a key/value pair?

Map<String, Integer> vars = new HashMap<String, Integer>();
vars.put("width",5);
vars.put("area",8);
vars.put("potato", 2);
vars.put("stackOverflow",-4);

Then you could access the inputs like so:

vars.get(input); //would be 2
vars.get("stackOverflow"); //would be -4

1 Comment

Don't forget it has to be a Map<String, Integer> in Java.
3

I have a solution for this problem that does not involve using a map. I ran into this technique because we had several variables that needed to be update based on something within the variable name itself. However, the best way to do this is by using the getters/setters rather than the variables.

After you create your class, you can access the methods by creating Method objects and invoking them individually.

public class FooClass

private String foo1;
private String foo2;

public String getFoo1();
public String getFoo2();

FooClass fooClass = new FooClass();

Method mFoo1 = fooClass.getClass().getMethod("getFoo" + increment + "()");

mFoo1 .invoke(fooClass);

However, this would not be limited to only incremental numbers, as long as you can get the string to match the method exactly.

String value = "Potato";
Method mPotato = myClass.getClass().getMethod("get" + value+ "()");

mPotato.invoke(myClass);

1 Comment

Thanks for the answer. My findings show that you don't need the parenthesis when looking up the method. Also you should use getDeclaredMethod() if you're looking for private methods - getMethod() only finds public methods.
2

I have another solution without a map :

class Vars {
    Integer potato, stack;
    public Vars(a,b) {
        potato=a;
        stack=b;
    }
}
Object object=(Object)new Vars(1,2);
Class<?> c = object.getClass();
Integer result=(Integer)c.getField("potato").get(object);

Comments

0

Very redundant, but you can keep your variable names when using a map:

int width = 5;
int area = 8;
int potato = 2;
int stackOverflow = -4;
Map<String, Integer> map = new HashMap<>();
map.put("width", width);
map.put("area", area);
map.put("potato", potato);
map.put("stackOverflow", stackOverflow);

But a statement like this:

width = 42;

would not change the value in the Map:

String input = "width";
map.get(input); // <-- still returns 5.

Only a new call of put fixes that:

width = 42;
map.put("width", width);
// or
map.put("width", 42);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.