Is it possible to store the name of an int variable in a string and use that string as a parameter to update the int?
Yes, this is called reflection.
You are interested in the Field class.
Example:
static class A {
public int x = 0;
}
public static void main(String[] args) throws Exception {
A a = new A();
Field f = A.class.getField("x");
f.set(a, 5);
System.out.println(a.x);
}
Note that though it is possible - it is not advised to use reflection except for rare cases, it has some major draw backs (maintainability, safety, performance...) - which makes the alternatives usually better choices.
Using reflection in this case would be overkill. You can obtain the intended behavior by simply using a Map:
Map<String, Integer> variables = new HashMap<String, Integer>();
Then the keys to the map will be the variable names, and the values the actual values:
variables.put("var1", 10);
variables.put("var2", 20);
Later on, you'll retrieve the values like this:
Integer n1 = variables.get("var1"); // n1 == 10
Integer n2 = variables.get("var2"); // n2 == 20
And if you need to update the values:
variables.put("var1", variables.get("var1") + 32);
Integer n3 = variables.get("var1"); // n3 == 42
The context of your question is not clear - a Map<String, Integer> might do what you need:
Map<String, Integer> map = new HashMap<String, Integer> ();
map.put("int1", 1);
map.put("int2", 2);
//now retrieve the ints based on their name
int int1 = map.get("int1");
Related
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)
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);
}
}
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.
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
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);
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);
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);
Is there a way to points several keys to the same value?
i.e.
HashMap<String, Float> mymap = new HashMap<>();
mymap.put("hello",5f);
mymap.put("bye",5f);
~somehow point bye and hello to the same value~
mymap.put("bye", mymap.get("bye") +5f)
mymap.get("hello") == 10
Java HashMap stores references to Objects. If you store same object with two different keys, the keys will point to the same value.
But that is not your problem. Your problem is that you are using Float values and Float is an immutable data type. You can not change it's value once it has been created. To achieve what you want to do you need to either create a mutable Float or store the float in a container and store that container in the map. One of the most simple containers would be a single element array (though I would only use it in an example code, never in a production code as it is error prone and it is "self undocumentable").
HashMap<String, Float[]> mymap = new HashMap<>();
Float[] val = new Float[] { 5f };
mymap.put("hello", val);
mymap.put("bye", val);
...
mymap.get("bye")[0] = mymap.get("bye")[0] + 5f;
mymap.get("hello")[0] == 10f
You would need a mutable object as Value for that, for example:
static class FLoatHolder {
private float f;
public FLoatHolder(float f) {
this.f = f;
}
public float getF() {
return f;
}
public void setF(float f) {
this.f = f;
}
}
Map<String, FLoatHolder> map = new HashMap<>();
FLoatHolder fh = new FLoatHolder(5f);
map.put("bye", fh);
map.put("hello", fh);
FLoatHolder holder = map.get("bye");
holder.setF(holder.getF() + 0.5f);
map.put("bye", holder);
System.out.println(map.get("hello").getF());
If you just want two keys to point to the same value, that is perfectly fine. Maps don't care what they point to, just that there aren't conflicting keys.
If you want to add the integer values together, then your pseudocode works as you intend.
If you want pointer like behavior where changing the value of key A affects the value of key B, then you'd have to make a wrapper object and use fields.
Something like:
class Pointer<T> {
private T t;
public Pointer(T t) {
set(t);
}
public void set(T t) {
this.t = t;
}
public T get() {
return t;
}
}
...
Map<String, Pointer> map = new HashMap<>();
Pointer<Integer> ptr = new Pointer<>(5);
map.put("A", ptr);
map.put("B", ptr);
System.out.println(map.get("A").get());
System.out.println(map.get("B").get());
ptr.set(25);
System.out.println(map.get("A").get());
System.out.println(map.get("B").get());
If you want something else you may need to elaborate or consider another data structure.
public static HashMap makeHashMap() {
HashMap<String, Integer> table = new HashMap<String, Integer>();
table.put("C", 1);
table.put("V", 2);
table.put("D", 3);
table.put("W", 4);
table.put("E", 5);
table.put("F", 6);
table.put("X", 7);
table.put("G", 8);
table.put("Y", 9);
table.put("A", 10);
table.put("Z", 11);
table.put("B", 12);
// System.out.print(table);
return table;
}
public static ArrayList<Object> makeArrayList(HashMap<String, Integer> table) {
Object[] keys = table.keySet().toArray();
ArrayList<Object> randomlyGeneratedNotes = new ArrayList<Object>();
for (int i = 0; i < 83; i++) {
Object key = keys[new Random().nextInt(keys.length)];
// System.out.println(key + " " + table.get(key));
randomlyGeneratedNotes.add(key);
}
System.out.println(randomlyGeneratedNotes);
return randomlyGeneratedNotes;
}
public static void pitchMovement(ArrayList<Object> randomlyGeneratedNotes, HashMap table) {
Iterator<String> keySetIterator = table.keySet().iterator();
String key = keySetIterator.next();
int first = table.get(key);
for (Object o : randomlyGeneratedNotes) {
//you want to grab the values of 2 neighboring keys
if (table.containsKey(o)) {
// System.out.println("true");
Object firstNote= table.get(key);
System.out.println(firstNote);
}
}
}
}
How can I perform addition/subtraction between my HashMap values? Or did I use an inappropriate data structure? I tried doing something my pitchMovement method, but the int first = table.get(key); line gives an error of incompatible types:
Object cannot be converted to int.
Not sure if this is a simple error or a more complex one.
I'd like to encourage you to put some learning effort into understanding generics and interfaces. Java will be friendly in its conversion between primitives and value types (like int and Integer), but plays dumb when dealing with objects of type Object. The problem you're encountering in multiple places is that you're needlessly letting your strongly typed values degrade to type Object.
I'd suggest the following changes:
Change public static HashMap makeHashMap() to public static HashMap<String,Integer>. Otherwise, you'll get back the equivalent of HashMap<Object,Object>, which you don't want.
In public static ArrayList<Object> makeArrayList(HashMap<String, Integer> table), you're extracting the String typed keys from HashMap, and then converting them to type Object when building your array. Don't change their type-- keep them as String. You may have been thrown by "toArray()" converting to an array of Object values. You can use this technique to preserve the type:
String[] keys=new String[table.size()];
keys=table.keySet().toArray(keys);
In doing so, you can easily change the signature of makeArrayList to return an ArrayList of type String:
public static ArrayList<String> makeArrayList(HashMap<String, Integer> table)
Your pitchMovement signature could be changed to:
public static void pitchMovement(ArrayList<String> randomlyGeneratedNotes,
HashMap<String,Integer> table)
Note that the specific error you encountered related to HashMap table being defined without generic parameters (which is equivalent to HashMap<Object,Object>).
When your types haven't been reduced to Object, then Java will use "auto-boxing" to automatically convert between your int and Integer types as needed. The following, for example, is valid.
Integer x=new Integer(5);
int y=10+x;
Integer z=x+y;
In sum, math operations will work as you'd expect without you having to cast and convert between primitives and their equivalent value types, no matter where you store them, but you must take efforts to keep those types preserved wherever you use them.
Try
Integer first = table.get(key);
as table is a map of String and Integer, you can get the value as Integer.
You can then convert your Integer variable to int.
You need to update your method signature with generic parameters:
public static void pitchMovement(ArrayList<Object> randomlyGeneratedNotes, HashMap<String, Integer> table)
I need some help answering my own question, so I need to assign a int value to a character. I have looked and look through the api. I can not think of what I should do. I need to assign the character and int value designated by the user, he/she will assign any integer to and char they desire. At first I thought to type cast, but I can not get my type cast to work correctly. any ideas?
e.g.
F = 56
H = -25
There is already predefined values associated to characters and this is related to encoding. For example the value for A is 65, B 66, ... and you can't reprogramme it arbitrarly except by using a very low level programming technics. Now if you want to associate int values to characters you can use a Map.
for example
Map<Character, Integer> charValues = new HashMap<Character, Integer>();
charValues.put('H',-25);
charValues.put('F', 56);
And later while processing the map you can use for example
int valueForH = charValues.get('H');
The autoboxing and auto unboxing capacities of Java allows you to go transparently from the Character/Integer reference types to char/int value types
You can use this in an interactive fashion with the user via a main method or other method. Example
public static void main(String[] args) {
Map<Character, Integer> charValues = new HashMap<Character, Integer>();
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("Enter a character and the corresponding value...");
String data = sc.next();
if ("exit".equals(data)) {
break;
}
char car = data.charAt(0);
int correspondingValue = sc.nextInt();
charValues.put(car, correspondingValue);
}
// Here after exit you can use charValues.get(key) to get the int value associated with the key (a char value)
}
How do I store a set of paired numbers in java? Do I use lists or arrays or maybe something else?
eg. [ (1,1) , (2,1) , (3,5)]
There are a few options:
Write a custom IntPair class
class IntPair {
// Ideally, name the class after whatever you're actually using
// the int pairs *for.*
final int x;
final int y;
IntPair(int x, int y) {this.x=x;this.y=y;}
// depending on your use case, equals? hashCode? More methods?
}
and then create an IntPair[] or a List<IntPair>.
Alternately, create a two-dimensional array new int[n][2], and treat the rows as pairs.
Java doesn't have a built-in Pair class for a few reasons, but the most noticeable is that it's easy enough to write a class that has the same function, but has much more enlightening, helpful names for the class, its fields, and its methods.
If we knew more about what you're actually using this for, we might be able to provide more detailed suggestions -- for all we know, a Map could be appropriate here.
If you're using JavaFX, you can use the class Pair.
import javafx.util.Pair;
int x = 23;
int y = 98;
Pair<Integer, Integer> pair1 = new Pair<>(6, 7);
Pair <Integer, Integer> pair2 = new Pair<>(x, y);
Way 1 : Using javafx.util.Pair class
Pair<Integer> myPair1 = new Pair<Integer>(10,20);
Pair<Integer> myPair2 = new Pair<Integer>(30,40);
HashSet<Pair<Integer>> set = new HashSet<>(); // Java 8 and above
set.add(myPair1);
set.add(myPair2);
Way 2: Using int[] of size 2
int[] myPair1 = new int[] {10,20}; // myPair1[0]=10 , myPair[1] = 20
int[] myPair2 = new int[] {30,40};
HashSet<int[]> set = new HashSet<>(); // Java 8 and above
Way 3 : Converting pair into single number
int myPair1 = 10 * 1000 + 20;
// int first = myPair1 / 1000; second = myPair2 % 1000;
int myPair2 = 30 * 1000 + 40;
HashSet<Integer> set = new HashSet<>();
set.add(myPair1);
set.add(myPair2);
Way 4 : Using ArrayList instead of int[] in way 2
Way 5 : Custom class that uses HashSet and Pair internally
class Pair<T> {
T p1, p2;
Pair(T p1, T p2) {
this.p1 = p1;
this.p2 = p2;
}
Pair<Integer> pair = new Pair<Integer>(1,2);
int i1 = pair.p1;
int i2 = pair.p2;
You can also put in getters, setters, equals, hashcode, etc.
If you can live with low level structures and desperately need compact form of "literal" form of "set of pairs" -- this happens to me in unit test, when I need a set of fixtures -- you can simply use an array of arrays:
int[][] squares = {
{ 1, 1 },
{ 2, 4 },
{ 3, 9 }
};
But keep in mind that there is no semantic to such a type -- it all depends on proper use, compiler won't give you a warning if you type squares[0][1] when you really wanted squares[1][0].
If you're needing to avoid duplicates then a HashSet would be a good choice but it not then an ArrayList would work.
Class IntPair(){
int i;
int j;
}
HashSet<IntPair> set = new HashSet<IntPair>();
or
ArrayList<IntPair> list = new ArrayList<IntPair>();