I have the following piece of Java code using HashMap and generics:
import java.util.*;
import java.io.*;
public class Map{
static HashMap<Integer, Integer> imap;
static HashMap<Integer, Thing> tmap;
public static void main(String[] args){
imap = new HashMap<Integer, Integer>();
imap.put(0,0);
Integer i = imap.get(0);
i = i + 1;
System.out.println(imap.get(0));
tmap = new HashMap<Integer, Thing>();
tmap.put(0,new Thing(0));
Thing t = tmap.get(0);
t.a = t.a + 1;
System.out.println(tmap.get(0).a);
}
}
class Thing{
public int a;
public Thing(int n){
this.a = n;
}
}
which prints out the following:
0
1
I would expect it to print either both ones (if I were modifying the reference) or both zeros (if I were modifying the values). So why is the behaviour different for a map from integer to integer than from integer to thing?
Java's integer types are not mutable, so your first example takes the value from the map, then replaces the local variable with the new value. However, the second example gets a reference to the Thing instance from the map.
By doing i=i+1 you are incrementing not the value stored in the java.lang.Integer contained in the map.
I think i = i + 1; will not be updated on the object because the get will be a copy by value as you assigning to a primitive. The primitive update will therefore not reflect in the map as you don't hold a reference. With the next example in Thing you are directly assigning back to the public primitive of the Thing, so again by value - but you update the public int.
It's because you're auto-unboxing the Integer value when you grab it from the first map (by assigning an Integer to an int). At that point you're not using an Integer reference, you're using an int primitive, with no relationship to the Integer reference held in the map.
As java Integers are immutable, there's really no way to do what you're trying to demonstrate here. There is no way to modify the internal primitive int held by the Integer reference in the map. You'd have to .put a new Integer to change the value held at key 0.
Answering the second part of the question ("But then why does it print 1 on the second print statement?"), it's because the lines ...
Thing t = tmap.get(0);
t.a = t.a + 1;
... get you a reference to the object located within the hashmap at a given location, and then modify a member variable of the referenced object. The println statement then retrieves another reference to that same object with the now-modified member variable.
Related
In the code bellow I excpected the Output to be true, 0. However the output is true, 1. Since cnt is a reference variable to the Value of the Key-Value Pair with Key 3. I thought the operation cnt--; would change the value where the reference variable is pointing at. However the experimental code shown bellow doesn't seem to change the value in the HashMap.
I'm confused because if get method returns a copy of the instance, then the equals operation should return false. Yet it is returning true so it is just returning a reference to an instance. Then why is that unary decrement operation not working?
Thank you in advance. Any feedback to the clarity of the question is welcome.
import java.util.HashMap;
import java.util.Map;
public class Equals {
public static void main(String[] args) {
int[] nums1 = new int[] { 1, 2, 3, 4, 5 };
Map<Integer, Integer> map = new HashMap<>();
for (int n : nums1) {
map.put(n, map.getOrDefault(n, 0) + 1);
}
Integer cnt = map.getOrDefault(3, 0);
Integer cnt2 = map.get(3);
System.out.println(cnt.equals(cnt2));
cnt--;
System.out.println(cnt2);
}
}
The -- operation is an operation on a variable. In the case of an Integer variable, it updates the variable to a new reference value ... representing the number - 1. It is equivalent to
// cnt--;
cnt = Integer.valueOf(cnt.intValue() - 1);
The -- operator cannot change the value held within the existing Integer object. Integer objects are immutable!
So ... when you increment the variable, it doesn't affect the value in the HashMap entry.
Ok, so i have to create a recursive method for counting the nodes in a tree, and i did this (variable names are in portuguese, sorry):
public int contaNos(Arvbin r) {
Integer cardinalidade = 0;
contaNosPrivado(r, cardinalidade);
return cardinalidade;
}
private void contaNosPrivado(Arvbin r, Integer cardinalidade) {
if (r==null) {
return;
}
cardinalidade=cardinalidade+1;
contaNosPrivado(r.esq, cardinalidade);
contaNosPrivado(r.dir, cardinalidade);
return;
}
Arvbin is the binary tree, esq and dir are the left and right references to the tree's branches.
I thought this would work, but for some reason when i try to run it, it returns 0. I've usen a little bit of debugging and i think the issue is that when the methods finish and come back to the original non-recursive one, the cardinalidade variable is set to 0. I'm not sure if it's because autoboxing is messing with my Integer and turning it into an int, and then when i call the method it passes a copy of the value instead of the reference to the existing object, and i don't know how to fix it. If anyone could help, i'd greatly appreciate it
The problem is that wrapper classes are immutable in Java. cardinalidade is just a parameter of contaNosPrivado here and, unfortunately, cannot act as an argument like other object type parameters can, i.e. this local reference cannot change inner fields of the object that initial reference refers. Any change to it affects it only the way it affects any primitive local variable.
What exactly happens inside your contaNosPrivado:
On invocation, it is indeed supplied a reference to an Integer object. This reference is assigned to a local variable named
cardinalidade.
In this line:
cardinalidade=cardinalidade+1;
this object is first unboxed to a primitive int variable, this variable is incremented afterwards, and
finally the result is reboxed into a new Integer object which is
then assigned to cardinalidade. There is no way to 'increment'
original object, even if you use the increment operator:
cardinalidade++;
Any further processing applies to the newly created Integer object and doesn't affect the reference passed to contaNosPrivado.
To achieve your goals, use something like this instead:
static int contaNosPrivado(Arvbin r) {
if (r == null)
return 1;
else
return contaNosPrivado(r.esc) + contaNosPrivado(r.dir);
}
As #John McClane has pointed out, you can't pass an Integer argument by reference, only by value.
But there's also no need for a private helper method, you can just simplify it all to a single method:
public int countLeaves( BinaryTreeNode n )
{
return n == null? 0 : ( countLeaves( n.rightLeaf ) + countLeaves( n.leftLeaf ) );
}
Or (excuse my poor Portugese):
public int contaNos( Arvbin r )
{
return r == null? 0 : ( contaNos( r.esq ) + contaNos( r.dir ) );
}
I have a class named MyVisitor that extends another class named Value. In one of my methods in MyVisitor, I have to store an array of Values in a HashMap. However, since the MyVisitor only extends Value, I can't return Value[ ] in the HashMap. Due to my limited knowledge on Java this is the solution I found:
In my Value class, I have:
public static int x;
public static Value ARRAY = new Value(new Object[x]); // I assume this would return an array of Objects of size x?
public Object[] objArray(){
return (Object[])value;
}
In MyVisitor class, I have this HashMap:
public Map<String, Value> array_memory = new HashMap<String, Value>();
In MyVisitor class, I have a method named array that uses Value.ARRAY like so:
Value.x = x; //Would change the value of public static int x in class Value
return array_memory.put(id, Value.ARRAY);
I have another method named arrayDec that calls array and does the following:
array(ctx);
String key = ctx.ID().getText();
Object[] val = array_memory.get(key).objArray();
System.out.println(val.length);
val.length prints 0
I have the following question:
Does = new Value(new Object[Value.x]); actually create an array of Objects of size x and masks it as Value?
Also, does Value.ARRAY actually return an array of Objects of size x?
Why does val.length return 0?
Confused? yeah me too :(
Also, if you're wondering why I'm doing this, I have a project in one of my courses that requires us to create our own compiler/interpreter. I'm trying to implement arrays. I'm using antlr4 to help me with it (thus the ctx.ID().getText() in one of the snippets there)
Any help would be appreciated. And if you have a better idea of how I should implement this I'm open to suggestions. Or if you know any links about implementing arrays in antlr4 that would be awesome as well. Thanks!
No. It creates an instance of Value. This instance might hold an array of Object if you have defined a constructor that takes an Object array as a parameter and assign that parameter to a member.
No. It returns an instance of Value
Impossible to say. Your code doesn’t explain how the member ‘value’ is defined or assigned.
Basically I have a variable, zlort = one;
I want to concatenate the value of zlort into a variable (object reference) name.
Like
BankAccount Accountzlort = new BankAccount;
I want the zlort in Account.zlort to actually be the replaced with value of zlort (one--meaning I want the value to be Accountone), and not zlort itself.
Is it possible to do this?
Thanks!
No you can't, but you might put the instance in a map:
Map<String,BankAccount> map = new HashMap<String,BankAccount>();
map.put("Account" + zlort, new BankAccount());
If you mean dynamically choosing the name to assign a variable to, then no.
You could use a HashMap to achieve the same effect.
It is not possible to change the name of a variable at runtime. That would lead to extreme security and stability problems when dealing with any real-world application.
However, as the two answers here have mentioned, a HashMap might acheive what you are looking for. (See the javadoc!!)
A HashMap (or any other map, for that matter) maps a Key to a Value. The concept is similar to a variable, which is a name -> value mapping. The only difference is that variables are part of the actual program code, which is effectively unmodifiable after compiling. A Map is a data structure that can be modified by the running program. This allows you to freely add key-value pairings to it.
Note that in Java, type-safety is encouraged through the use of Generics. Basically this ensures that the key can only be of one type (e.g. String) and the value can be of only one type (BankAccount). A thorough coverage of Generics can be found here.
You would declare this as follows:
Map<String, BankAccount> accounts = new HashMap<String, BankAccount>();
And then to add a key-value pair to the map, you would use the put() method (which 'puts' a value into the map, associated with a key)
String key = "Key"
BankAccount value = new BankAccount();
accounts.put(key, value);
To retrieve it, you would use the get() method.
BankAccount retrievedValue;
retrievedValue = accounts.get(key);
After reading the explanations in your comments, the fact that you can't use an array but can use an `ArrayList'...
Rather than creating a new variable name (or array element, or map value) for each BankAccount, you can probably use scope to your advantage.
Scope is the concept that a reference to a variable only has meaning within a certain part of code. If you declare a variable inside a method, that variable can only be seen within that method. A variable declared within a block (a loop, if statement, etc ) can only be seen from within that block.
Class fields have a different kind of scoping that can be adjusted with keywords (see here).
For example:
public class ScopeExample
int classInt = 10;
public void method() {
int methodInt = 0; // This integer can only be seen by code in
// this method
}
public void method2() {
//doSomething(methodInt) // This line won't compile because i is
// declared in a different method!
doSomething(classInt); // This line will compile and work
// because x is declared in the class that
// contains this method.
int index = 0;
while (index < 3) {
int whileInt = index; // This integer can only be seen from within
// this while loop! It is created each
// loop iteration.
doSomething(whileInt);
}
doSomething(whileInt); //This line won't work, whileInt is out of scope!
}
public doSomething(int a) {
System.out.println(a);
}
}
SO! If you create a BankAccount object within the loop, you don't have to worry about creating a new name for the next one. Each time the loop iterates it will become a new object (when you create it).
If you have to store it, you definitely will need to use an array or other data structure (ArrayList!).
Building on the idea of scope, you -can- have the same variable name for each new BankAccount. A variable reference name isn't guaranteed to be paired with the object that it refers to. That is a convenience to the programmer, so you don't have to know the exact memory address it is being stored in.
For example:
public static void main(String[] args) {
Object o;
int i = 0;
while (i < 5) {
Object reference = new Object(); // Create a new Object and store
// it in 'reference'
o = obj; // The Object 'o' now refers to the object in 'reference'
i++;
}
System.out.println(o); // This should print information about the
// LAST object created.
}
The new Object created in the loop does not belong to 'obj'. You as a programmer use 'obj' to point to the Object. The program doesn't really know what obj means, other than the fact that it points to the Object you just created.
Finally, you can use this along with an ArrayList to make your life easier.
public static void main(String[] args) {
// Our new ArrayList to hold our objects!
ArrayList<Object> stuff = new ArrayList<Object>();
int i = 0;
while (i < 5) {
Object obj = new Object(); // Create an object and make obj point to it.
stuff.add(obj); // Put "the object that 'obj' points to" in 'stuff'.
i++;
}
// This loop goes through all of the Objects in the ArrayList and prints them
for (int index = 0; index < stuff.size(); index++) {
System.out.println(stuff.get(i)); // This will print a single
// object in the ArrayList each time.
}
}
How do I increment a Integer's value in Java? I know I can get the value with intValue, and I can set it with new Integer(int i).
playerID.intValue()++;
does not seem to work.
Note: PlayerID is a Integer that has been created with:
Integer playerID = new Integer(1);
Integer objects are immutable, so you cannot modify the value once they have been created. You will need to create a new Integer and replace the existing one.
playerID = new Integer(playerID.intValue() + 1);
As Grodriguez says, Integer objects are immutable. The problem here is that you're trying to increment the int value of the player ID rather than the ID itself. In Java 5+, you can just write playerID++.
As a side note, never ever call Integer's constructor. Take advantage of autoboxing by just assigning ints to Integers directly, like Integer foo = 5. This will use Integer.valueOf(int) transparently, which is superior to the constructor because it doesn't always have to create a new object.
Java 7 and 8. Increment DOES change the reference, so it references to another Integer object. Look:
#Test
public void incInteger()
{
Integer i = 5;
Integer iOrig = i;
++i; // Same as i = i + 1;
Assert.assertEquals(6, i.intValue());
Assert.assertNotEquals(iOrig, i);
}
Integer by itself is still immutable.
AtomicInteger
Maybe this is of some worth also: there is a Java class called AtomicInteger.
This class has some useful methods like addAndGet(int delta) or incrementAndGet() (and their counterparts) which allow you to increment/decrement the value of the same instance. Though the class is designed to be used in the context of concurrency, it's also quite useful in other scenarios and probably fits your need.
final AtomicInteger count = new AtomicInteger( 0 ) ;
…
count.incrementAndGet(); // Ignoring the return value.
Integer objects are immutable. You can't change the value of the integer held by the object itself, but you can just create a new Integer object to hold the result:
Integer start = new Integer(5);
Integer end = start + 5; // end == 10;
For Java 7, increment operator '++' works on Integers. Below is a tested example
Integer i = new Integer( 12 );
System.out.println(i); //12
i = i++;
System.out.println(i); //13
Maybe you can try:
final AtomicInteger i = new AtomicInteger(0);
i.set(1);
i.get();
You can use IntHolder as mutable alternative to Integer. But does it worth?
All the primitive wrapper objects are immutable.
I'm maybe late to the question but I want to add and clarify that when you do playerID++, what really happens is something like this:
playerID = Integer.valueOf( playerID.intValue() + 1);
Integer.valueOf(int) will always cache values in the range -128 to 127, inclusive, and may cache other values outside of this range.
After Java 8, we can use as below
import java.lang.Math;
Math.incrementExact(playerID);
//it increment the integer value to + 1. It is also available for long