Why is this HashMap being passed as reference [duplicate] - java

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
I have two HashMaps defined as follows:
HashMap EventTable = new HashMap();
HashMap MainTable = new HashMap ();
Now, suppose I insert some data into EventTable:
EventTable.put("name", "Test Event Name");
Then, suppose we insert the EventTable into the MainTable:
MainTable.put("table", EventTable);
and then print out MainTable:
{table={name=Test Event Name}}
Now if I modify Event Table as follows:
EventTable.put("more names", "More test events");
This changes the MainTable as well:
{table={more names=More test events, name=Test Event Name}}
So obviously, EventTable is being passed by reference to MainTable.
I don't understand why EventTable is being passed by reference.
Ideally I would like to reuse the EventTable HashMap to create other entries, while retaining my old entries, so I would like to pass EventTable by value.
EDIT:
Forgot to mention this in the main question, but when I add a String to the MainTable, that does not change when I modify the string afterwards. So how is the behavior is different for the String?

Although I would never use raw types and follow the Java naming conventions, you can do something like this to get your desired behavior:
mainTable.put("table", new HashMap(eventTable));
To address your edit: Strings are immutable in Java.

It is because, even though Java passes all arguments by value, when you pass an object, you are really passing an object reference. if you were to set EventTable to a new Hashmap, the one you passed in to MainTable would not be changed. This article may help clear things up: http://javadude.com/articles/passbyvalue.htm

as in #assylias said, parameters passed by value.
here HashMap can not copy the date because it could be anything. but you can create a new HashMap by its constructor.
HashMap newHashMap= new HashMap(oldHashMap);

Related

Using lambdas to extract an Object attribute contained in an ArrayList [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I have made a class called User with two string attributes: Login and Password.
I have a database (userList, of type ArrayList<User>) with all the existing users, and I want to know if a login is already used or not.
I tried to use lambda expressions in order to do that, but it doesn't work:
ArrayList<String> loginList = null;
userListe.forEach(x->loginList.add(x.getLogin()));
How do I solve this?
Assuming userListe is a List:
List<String> loginList = userListe
.stream()
.map(x -> x.getLogin())
.collect(Collectors.toList));
Explanation:
It is better to use a List instead of ArrayList because it is always preferable using interface instead of concrete types. First, using a stream you create a flow of User objects. Using map you get a field from your objects using the appropriate getter. At last, using a collect you can collect all objects returned by map method, in this case String object.
Your loginList is null, so the first forEach will throw a NullPointerException. Also, remember that it is better to have pure function in lambdas, with no side effects. Using stream and collect allows you to get a List of objects you need without having functions with side effects.

Trouble using HashMaps with ArrayList [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 7 years ago.
I am having trouble with implementing HashMaps with ArrayListsin my java class. The thing is it keeps adding objects to the ArrayList is the HashMap even though I am not updating my HashMap.
This is the code that I can not understand how works:
HashMap<String, ArrayList<String>> map = new HashMap<>();
ArrayList<String> array = new ArrayList<String>();
array.add("One");
array.add("Two");
map.put("Key", array);
array.add("Three"); //2. Why does this get added to the HashMap?
System.out.println(map1.get("Key"));
//1. This print out [One, Two, Three].. When it should be [One, Two]!
The ArrayList is passed by reference to the map.put() call. It means no copying, after the call your array variable refers to the same object. If you copy when adding the entry then it will work: map.put("Key", new ArrayList<String>(array));
map.put("Key", array);
That means you are adding a reference of list to the map. Hence the changes to that reference can be seen everywhere.
If you don't want to do that, create a new list and add to it.
This is the expected behaviour. You put the list into the map, not a copy, the list itself. So if you later modify the list, the list inside the map (which is the actual list) will also be modified.
Because you add a reference to a list into your map, and you still hold the original reference, when you amend that list, you're amending the list referenced within the map.
Remember that Java passes references to objects around (not copies), and if you have a mutable object referenced within a container, that object can still be changed.
If you want to avoid this behaviour, you need to make a defensive copy. Note that this applies to mutable objects generally (not just collections) and you need to be clear when you pass references around and hold them, that anyone else holding that reference can change/mutate your object without your control. It's often preferable to create and pass around immutable objects instead
you are adding a reference of your ArrayList as the value to your map.
so if you want only the first two value, you can simply point your ArrayList to null to ensure you don't add stuff to it then re-initiate it
HashMap<String, ArrayList<String>> map = new HashMap<>();
ArrayList<String> array = new ArrayList<String>();
array.add("One");
array.add("Two");
map.put("Key", array);
array=null; //note this isn't really necessary, just a precaution that you won't change the value of arraylist inside the map using this refrence
array=new ArrayList<String>(map.get("key"));
array.add("Three");
System.out.println(map1.get("Key"));
output:
[one, two]

Confused about Java passing methods (by value or reference) [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 8 years ago.
guys,
Please, can you clarify something for me?
As i understand (please correct me if i am wrong), when i pass the variables to a method or class i'm passing by value, isn't it?
if it's true, then why does Java has method .clone()?
Why do i ask this question, because i am very confused...here is the code:
if i pass variables using the following code and then modify them inside the dialog, the original values (outside) are also changed.
DialogChoosePayment mDialogChoosePayment = new DialogChoosePayment(mContext, (ArrayList<Payment>) defaultValues.getPayment(), (ArrayList<Payment>) selectedValues);
mDialogChoosePayment.show();
But, if i use the following one, then the variables values (Original variables from outside) are not changed.
DialogChoosePayment mDialogChoosePayment = new DialogChoosePayment(mContext, (ArrayList<Payment>) defaultValues.getPayment().clone(), (ArrayList<Payment>) selectedValues.clone());
mDialogChoosePayment.show();
Please, explain it to a newbie =)
Source: http://docs.oracle.com/javase/tutorial/java/javaOO/arguments.html
Passing Primitive Data Type Arguments Primitive arguments, such as an int or a double, are passed into methods by value. This means that any changes to the values of the parameters exist only within the scope of the method. When the method returns, the parameters are gone and any changes to them are lost.
Passing Reference Data Type Arguments Reference data type parameters, such as objects, are also passed into methods by value. This means that when the method returns, the passed-in reference still references the same object as before. However, the values of the object's fields can be changed in the method, if they have the proper access level.
Java passes parameters by value. There are a lot of references on this topic. The most popular example is that you cannot simply implement method swap() that accepts 2 arguments and swaps their values.
The confusion may be caused by missunderstanding that the line like:
Object x = new Object();
indeed creates object but assigns reference to it to the variable x, so x is a reference. But if the you pass x to method you pass reference by value (or value of reference if you want).
This can give yo a tip why do we need method clone(). We need it when we want to create other object similar to the first one. Similarity means that it contains the same data and depends on the clone implementation (deep or not). But this is a absolutely another discussion.
Java has pass-by-value and only pass-by-value. At the same time Java has pointers (officially called references); so when't your passing an object to a method you're basically passing by value the variable that references that object.
If you modify the object then the object is seen to be modified at the called site. If you modify the reference to that the object in the called method, then this is not seen at the called site.
In your second case you create new objects with .clone() and pass them. Since there are no other references only in the called site, the changes can only be seen there.
when you pass (ArrayList<Payment>) defaultValues.getPayment(), you are actually passing reference to the array list. Any modifications using that reference will be reflected back to your list.
When you pass (ArrayList<Payment>) defaultValues.getPayment().clone(), you are creating a clone of the array list and passing reference to the cloned list. Any changes will be reflected only to the cloned array list not with the original array list.
In the first case you have copy of references to the objects. Surely you can change state of those objects.
In the second case you have copy of references too. But those references point to the new cloned objects.

HashMap data is deleted unexpectedly [duplicate]

This question already has answers here:
Is Java "pass-by-reference" or "pass-by-value"?
(93 answers)
Closed 9 years ago.
I'm creating a HashMap as follows:
private HashMap <String, JSONArray> HiveMap;
HiveMap = new HashMap <String, JSONArray>();
and also a private class variable to store some calculated data which will be put into the HashMap after the calculations are done:
private JSONArray hiveList;
After hiveList is calculated, I put the hiveList into the created HashMap (HiveMap):
HiveMap.put(hiveNode,hiveList);
When I print out HiveMap now, the output I get is as expected, with both the fields hiveNode and hiveList existing in the Hashmap. <"hiveNode":"hiveList">
After this is done, I assume that the data I put into the HashMap from hiveList is going to persist, so I clear the hiveList array using hiveList.clear();
But when I print the Hashmap after clearing hiveList, I see that the data from hiveList is gone from the HashMap as well.
Printing the HashMap after clearing hiveList results in: <"hiveNode": >
I don't understand this behavior, I would appreciate it if someone could shed some light on this.
The error is this:
After this is done, I assume that the data I put into the HashMap from hiveList is going to persist, so I clear the hiveList array using hiveList.clear();
What got passed to the hash map is the reference to the list, not a copy of it.
The most simple fix is to create a new instance instead of clearing it. Alternatively you can make a copy, and put that in the map.
The hiveList list and the list that resides as a value in the Map are one and the same, both the variable and the Map are holding references to the same object; if you clear() one list, the other is also emptied - there's a single list, not two.
If you have to clear and reuse hiveList for some reason (and I don't see why), then you'll need to put a different list in the Map, here's how to do a shallow copy:
HiveMap.put(hiveNode, new ArrayList<Hive>(hiveList));
Replace <Hive> with the actual type of the elements in the list.
In java objects are passed by copy of reference and not copy of object. So if you modify the object using reference at one place it get affected at all the places where this object is referred. In you case hiveList.clear();
is causing to remove all the elements of the list which is also referred at HiveMap.put(hiveNode,hiveList);and hence is eventually removed from the map.
That's how java manages the Object. What you have is the reference to that object and you only stored a reference to it. So, if you clear the object after storing it in the hashmap, the object from hashmap would also be cleared.
When you create an object java stores the reference along with the object at the same location in the memory. Hence, there's only one reference to that object. So, the result was expected
//Stores the reference to the object
HiveMap.put(hiveNode,hiveList);
//Modifies the same object in the memory
hiveList.clear();
You may want to read about Pass by reference and Pass by Value

All elements of An ArrayList change when a new one is added? [duplicate]

This question already has answers here:
Why does my ArrayList contain N copies of the last item added to the list?
(5 answers)
Closed 6 years ago.
First of all, apologies for not being able to supply any sourcecode. My project is pretty big and linking everything would be impractical, and I have not been able to scale down the problem which is exceedingly annoying. I will do my best to explain it here.
I am dynamically creating new instances of a class on each loop in my code. This instance is dynamically given a couple of properties while in the loop, 'name' for example. At the end of each loop, the newly generated instance is added to an ArrayList held in a another, 3rd, class.
The problem however is that when a new element is added, for whatever reason, all previous elements change to match exactly the latest. My guess is that the ArrayList is creating a reference to the dynamically created element so that whenever it changes, they all change, but I do not know how to fix this.
I would be grateful for any advice and apologies again for the quality of this explanation. I will post any specific piece of the code you may wish to see
As Requested -
XmlHandler.java - http://pastebin.com/mGmWt1RD
ParsedDataSet.java = http://pastebin.com/k1xb3KBe
Content.java = http://pastebin.com/UxiL2f9q
Just to cut down on your comprehension time - The project is an epub reader. The XMLHandler is being called from a SAX parser in another class not shown. The XMLHandler is used 3 different times for 3 different XML sets so there is some clutter there.
The problem lies with the 'toc' ArrayList. The 'toc', or TableOfContents, holds the Contents instances to be referenced later (not shown). I am trying to pass data each new instance of 'Content' and then pass that into the static ArrayList
I've seen folks report this kind of problem many times, and it always comes down to this: you're actually not creating a new instance, but instead using the same one for each iteration of the loop. It's an easy mistake to make, especially if you're coming from a language with different copy semantics. There are a number of different ways you can make this mistake; if you edit your question to show the loop code, I'm sure I'll be able to explain what's happening.
OK, now that you've added the code: the problem is that in "Content", all the data member are marked "static". In Java, that means that there's one variable shared by all objects -- i.e., the variable has the same value for every object. SO in fact you are creating many Content objects to put in the ArrayList, but they all look identical! Remove those "static" attributes from Content's data members, and you'll be all set.
ArrayList just stores reference of elements. Ensure that your code looks like:
ArrayList list = new ArrayList<>();
loop(...) {
MyObject newOne = new MyObject();
newOne.setXXX(xxx);
list.add(newOne);
}
Wrong code:
ArrayList list = new ArrayList<>();
MyObject sameOne = new MyObject();
loop(...) {
sameOne.setXXX(xxx);
list.add(sameOne);
}

Categories

Resources