In the following example:
public static void main(String[] args){
List<String> list = new ArrayList<String>();
list.add("hi");
list.add("hi");
list.add("hi");
list.remove("hi");
System.out.println(list); //prints [hi, hi]
}
The ArrayList is reduced by one but which one does it remove? Does it remove the last inserted or the earliest inserted one?
Since List#add()
is documented to add to the end of the list, and List#remove(Object)
is documented to return the first matching item it encounters, your call above will remove the earliest inserted instance of the string "hi."
Since the printed representation of the three objects in the list are all the same, it's hard to see the difference in behavior. However, if you look at the instance addresses in a debugger, noting which one entered the list first, you'll confirm that it's also the first—and only—one to be removed.
In your case, given that you're using string literals, they are interned by the compiler (per §3.10.5 of the JLS), so you'll see three of the same instance present in your list. In order to produce distinct String
instances, try changing your three insertion calls to the following:
/* not final */ String h = "h";
list.add(h + "i"); // not interned, instance 1
list.add(h + "i"); // not interned, instance 2
list.add(h + "i"); // not interned, instance 3
Compare what you see in the debugger using those statements with your original program. Do you see a difference?
Note that if the String
instance h
above is declared as final, then the three concatenations will in fact all be interned, yielding the same String
instance being added to the list three times. Thanks to @xehpuk for correcting my initial mistake regarding the final qualifier.