web-dev-qa-db-fra.com

Obtenir la variable par nom à partir d'une chaîne

Exemple de code:

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

Maintenant, disons que je veux que l'utilisateur entre une chaîne:

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

Ensuite, supposons que l'utilisateur entre potato. Comment pourrais-je récupérer la variable nommée potato et faire des choses avec? Quelque chose comme ça:

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

J'ai cherché des choses et je n'ai pas trouvé beaucoup; J'ai trouvé une référence à quelque chose appelé "l'API de Reflection", mais cela semble trop compliqué pour cette tâche simple.

Y a-t-il un moyen de faire cela, et si oui, de quoi s'agit-il? Si "Réflexion" fonctionne vraiment et si c'est le seul moyen, alors, comment l'utiliserais-je pour le faire? La page de tutoriel qui y est consacrée contient toutes sortes de choses internes que je ne peux comprendre.

EDIT: Je dois garder le Strings dans les variables pour ce que je fais. (Je ne peux pas utiliser une Map)

10
Doorknob

Utiliser la réflexion ne semble pas être une bonne conception pour ce que vous faites ici. Il serait préférable d'utiliser un Map<String, Integer> par exemple:

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

Ou avec Goyave :

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

Ou avec un 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);
    }
}
15
Paul Bellora

Au lieu d'essayer de trouver la valeur d'un nom de variable, pourquoi ne pas utiliser une carte avec une paire clé/valeur? 

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

Ensuite, vous pouvez accéder aux entrées de la manière suivante:

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

Les noms de variables ne sont disponibles qu'au moment du compilateur. Reflection ne donne accès qu'aux déclarations de classe et aux éléments déclarés à l'intérieur de celles-ci, mais pas aux variables locales. Je soupçonne qu'un Map sera une solution plus appropriée à votre problème réel. Plus précisément, consultez HashMap et TreeMap.

2
Code-Apprentice

Très redondant , mais vous pouvez conserver vos noms de variables lorsque vous utilisez une carte:

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

Mais une déclaration comme celle-ci:

width = 42;

ne changerait pas la valeur de la carte:

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

Seul un nouvel appel de put réparer cela:

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

J'ai une autre solution sans carte: 

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

J'ai une solution à ce problème qui n'implique pas l'utilisation d'une carte. J'ai rencontré cette technique parce que nous avions plusieurs variables à mettre à jour en fonction de quelque chose dans le nom de la variable elle-même. Cependant, la meilleure façon de procéder consiste à utiliser les getters/setters plutôt que les variables.

Après avoir créé votre classe, vous pouvez accéder aux méthodes en créant des objets Méthode et en les appelant individuellement.

public class FooClass

private String foo1;<br>
private String foo2;<br>

public String getFoo1()<br>
public String getFoo2()<br>

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";<br>
Method mPotato = myClass.getClass().getMethod("get" + value+ "()");

mPotato.invoke(myClass);
0
Robert Greathouse