tckmn
tckmn

Reputation: 59363

Get variable by name from a String

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)

Upvotes: 21

Views: 61795

Answers (6)

Robert Greathouse
Robert Greathouse

Reputation: 41

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

Upvotes: 3

Luatic
Luatic

Reputation: 11231

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

Upvotes: 2

mbumiller
mbumiller

Reputation: 114

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

Upvotes: 3

Paul Bellora
Paul Bellora

Reputation: 55233

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

Upvotes: 17

jlordo
jlordo

Reputation: 37853

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

Upvotes: 0

Code-Apprentice
Code-Apprentice

Reputation: 83607

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.

Upvotes: 4

Related Questions