3

I observed that ArrayList reflects the latest value but for String, it does not

//Initializing List and String
ArrayList<String> list = new ArrayList<String>();
list.add("Item1");
String name = "String1";

//Setting Attribute for both
session.setAttribute("mylist", list);
session.setAttribute("myname", name);

//getting attribute for both
out.println("<br> Printing intial valus <br>");
list = (ArrayList<String>)session.getAttribute("mylist");
for (String s:list){
 out.println(s);
}
name = (String) session.getAttribute("myname");
out.println(name);

//updating the values for both
list.add("Item2");
name = "String2";

//Need to add session.setAttribute again for String
//for it to reflect updated value "String 2"
//session.setAttribute("myname", name);

//getting attribute value after the update
list = (ArrayList<String>)session.getAttribute("mylist");
name = (String) session.getAttribute("myname");

//printing the value for both again
out.println("<br><br><br> Prining updated values <br><br>");
for (String s:list){
 out.println(s);
}
out.println(name);

The output of the below is

Printing intial valus 
 Item1 String1 

 Prining updated values 
 Item1 Item2 String1 Session 2

In the updated values part, shouldn't it print "String2", but for ArrayList it's printing "Item2" as well. If I manually add session.setAttribute("myname", name) just after updating String name values then it prints "String2". But this session.setAttribute is not required for the ArrayList

michael
  • 661
  • 1
  • 7
  • 18
  • I think what's going on is the value of `name` is getting copied when you add it to the session attributes. That's why you don't see it update until you add it again. Whereas `list` points to an object that does get updated when you call `add()`, hence why you see the update without doing anything further. – markspace Oct 28 '17 at 04:39

5 Answers5

2

When you pass object as an argument to Java's method - value of its reference copied and passed to it. ArrayList is mutable, so:

List<String> list = new ArrayList<String>();
// copy of object reference passed to session
session.setAttribute("list", list);
// adding new value to same object, so all references to it will see the chages
list.add("Something");

String type is immutable:

// object "value" created, reference passed to 'name' variable
String name = "value";
// copy of reference to object value passed to session
session.setAttribute("string", name);
// NEW object "otherString" created and its reference assigned to variable 'name'
// session still has it's copy of reference to "value" object
name = "otherString";
udalmik
  • 7,838
  • 26
  • 40
1

I think what's going on is the value of name is getting copied when you add it to the session attributes. That's why you don't see it update until you add it again. Whereas list points to an object that does get updated when you call add(), hence why you see the update without doing anything further.

This is easier to see if you pretend to implement the session attributes yourself. In most implementations, the attributes are just a HashMap:

HashMap<String,Object> attributes = new HashMap<>();

So if you add a string to this:

String name = "String1";
attributes.put( "myname", name );

You should see that the value of name is put into an EntrySet with values:

new EntrySet( "myname", name );

and the ctor will do something like

class EntrySet {
    Object key;
    Object value;
    EntrySet( Object key, Object value ) {
         this.key = key;
         this.value = value;
    }
}

Now I think it is easier to see that if you change name back in the original program, then the value of value does not update.

name = "String2"; // does nothing about the contents of EntrySet.value

But when you do the same thing for the ArrayList, clearly you have two references to the same object, so clearly the single object just updates.

ArrayList<String> list = new ArrayList<>();
list.add( "Item1" );
ArrayList<String> value = list;  // clearly both list and value point to the same object
value.add( "Item2" );  // the same list just gets updated

So that's why you see the list update without having to call setAttribute() again.

BTW, having an object "shared" like this (the list) is a huge multi-threading hole. If possible, you should be setting attributes on the request object instead. If not, you'll have to lock the session or provide some other form of mutex to keep everything safe and synch'd up.

markspace
  • 10,621
  • 3
  • 25
  • 39
1
ArrayList<String> list = new ArrayList<String>();
list.add("Item1");
String name = "String1";

The above lines create a variable named list that points to a location in memory (lets name that locatino LOC123) which has a list element "Item1" You also created a variable named name that points to a location in memory (lets name the locatino LOC456) which has a String value of "String1"

when you passed the name & list variables to the session.setAttribute method you only passed the reference values of the list & name variables. Now the session object is referring to LOC123 & LOC456 in memory, which allows it to retrieve the actual values.

When you executed the list.add("Item2"); command you added one more element to the same memory location LOC123. Given that the session is already pointing to LOC123, you managed to see the changed value reflected.

Java Strings are immutable, you can't change them once they are created. When you executed name = "String2"; you have created a new location in memory LOC789 which has the String value of "String2", and the name variable has now changed to point to LOC789.

Given that the session object still points at LOC456 and given that it knows nothing about LOC789, the updated "String2" value has not been reflected in the session.

To overcome this problem, you could use a StringBuffer (or StringBuilder) which can be edited.

H H
  • 366
  • 1
  • 6
0

It is because when you setAttribute to the session, if the value is a string, then your session is saving (copy) a string value in the memory. But, when the value is an ArrayList, then it save (copy) a pointer (memory location not the value) to that variable.

That's why when you get and change the value from the session, the pointer to the ArrayList is not change, only the value is change. So the session is still saving the right pointer. But, when you change a string, the value is change, and because session is saving the old value, it won't change automatically.

I Hope you understand my explanation.

Viki Theolorado
  • 546
  • 5
  • 17
  • That is not correct, reference passed to method for both String and ArrayList. The main difference that list.add(...) updates value of initial object, however String name = "new" assign new object to variable name without updating initial one. – udalmik Oct 28 '17 at 06:07
0

You can think like this, when you assign String2 to name like name = "String2"; the previous String object String1 looses its reference, but the session is still having value for attribute myname it is not returning null.

So while you write a code like session.setAttribute("myname", name); both name and attribute of session are in two different memory locations and that's why the changes in name won't be reflected in session.

You can check the special case of String class in this link What is the difference between “text” and new String(“text”)?

Arun Sudhakaran
  • 2,167
  • 4
  • 27
  • 52