Suppose I have a class :
class Dummy{
public static ArrayList<String> varArray;
}
In another class I do this :
Class Dummy2{
void main()
{
ArrayList<String> temp = Dummy.varArray;
}
}
Now suppose in Dummy2 I add elements to temp. Will the changes be reflected in Dummy.varArray? Because this is what is happening in my program. I tried printing the address of the two and they both point to the same address. Didn't know static field worked like this. Or am I doing something wrong?
Its not about static. The statement ArrayList<String> temp = Dummy.varArray; means that both variables are referring to the same arraylist. As varArray is static, it will have only one copy.
You can read ArrayList<String> temp = Dummy.varArray; as, The variable temp is now referring to the ArrayList object which is being referred by Dummy.varArray
By the way, you need to initialize it using public static ArrayList<String> varArray = new ArrayList<String>(); before you perform any operations on it.
ArrayList<String> temp = Dummy.varArray; will take what is known as a reference copy (or a shallow copy). That is, they will point to the same object.
It does not take a deep copy. See How to clone ArrayList and also clone its contents?
Yes it is behaving correctly.
When you do this
ArrayList<String> temp = Dummy.varArray;
Both pointing to the same reference ,since temp not a new list, you just telling that refer to Dummy.varArray
To make them independent, create a new list
ArrayList<String> temp = new ArrayList<String>(); //new List
temp.addAll(Dummy.varArray); //get those value to my list
Point to note:
When you do this temp.addAll(Dummy.varArray) at that point what ever the elements in the varArray they add to temp.
ArrayList<String> temp = new ArrayList<String>(); //new List
temp.addAll(Dummy.varArray); //get those value to my list
Dummy.varArray.add("newItem");// "newitem" is not there in temp
The later added elements won't magically add to temp.
The static keyword means there will only be one instance of that variable and not one variable per instance.
Related
Supposing we have:
public class Test {
private List<String> mWorkList;
private List<String> mOriginalList;
public Test(List<String> list) {
mWorkList = list;
mOriginalList = list;
}
public void updateData(List<String> newList) {
mWorkList.clear();
mWorkList.addAll(newList);
}
}
I want to change only mWorkList but mOriginalList is changed too when I call updateData(List<String>).
So how should I do it to keep mOriginalList as initially assigned in constructor?
In Java you pass variables by their reference. This means that whenever you do an assignment like mWorkList = list the variable mWorkList will point to the same place in memory where list is currently pointing. If you do mOriginalList = list, then mOriginalList will also point to that position. I.e. all three lists refer the same object at that point.
If you want independent lists you need to copy all values from the list to a new list like this:
List<String> myList = new ArrayList<>(otherList);
This constructor of ArrayList automatically adds all values from the other list, here is its documentation.
Your code could then look like:
public Test(List<String> list) {
mWorkList = new ArrayList<>(list);
mOriginalList = new ArrayList<>(list);
}
Or if you don't intent to change mOriginalList you could also leave it as mOriginalList = list. But then bear in mind that if the user makes changes to list (which comes from outside of your class) they will also be reflected in your mOriginalList which could easily lead to nasty bugs.
You are setting both list with the same instance reference with
mWorkList = list;
mOriginalList = list;
You need to create a new instance for mOriginalList by duplicating the list. This can be done with one of the constructor of ArrayList(Collection).
mOriginalList = new ArrayList<>(list);
Please note that the instances in both list are the same, so if you update an instance in list, it will be changed in mOriginalList. If you want to break that link too, you will need to clone the list and his content.
You should create new List object in function Test, because all your lists refer to one variable
public Test(List<String> list) {
mWorkList = new ArrayList<>(list);
mOriginalList = new ArrayList<>(list);
}
Whenever you assign a object to another object only the reference is assigned (Shallow copy). You should call copy constructor to make a deep copy.
public class Test {
private List<String> mWorkList;
private List<String> mOriginalList;
public Test(List<String> list) {
mWorkList = new ArrayList<>(list);
mOriginalList = new ArrayList<>(list);
}
public void updateData(List<String> newList) {
mWorkList.clear();
mWorkList.addAll(newList);
}
}
In java every variable is a reference, so in this case it's normal that both variable changes if you change one of them.
To keep a copy you have to create a new object and clone the original one.
Question: Why does the following print out:
ChildB___Parent of ChildB
ChildB___Parent of ChildB
Instead of what I think it should print out:
ChildA___Parent of ChildA
ChildB___Parent of ChildB
Short Self Contained Generalized Example of Issue:
import java.util.ArrayList;
import java.util.List;
public class StackExchangeQuestion1 {
public static void main(String[] args){
List<String[]> list = new ArrayList();
String[] pair = {"childID","parentID"}; //for readability this gets overwritten
//adding values to list
pair[0] = "ChildA";
pair[1] = "Parent of ChildA";
list.add(pair);
pair[0] = "ChildB";
pair[1] = "Parent of ChildB";
list.add(pair);
//checking values in list
for(int i=0;i<list.size();i++){
pair = list.get(i); //variable reuse for readability
System.out.println(pair[0]+"___"+pair[1]);
}
}}//end class and main
You are adding the same String[] reference twice to your list. Because of this, both elements in your list point to the same object. So, when you overwrote your array, you were really writing to the same piece of memory. The list was referencing this piece of memory twice, so you get 2 identical print statements.
Java will pass all non-primitive values by reference (that means it will pass a pointer to where a non-primitive object is stored in memory.)
If you were storing integers instead like so:
int a = 10;
list.add(a);
a = 20;
list.add(a);
Everything would be fine, because a is an interger, integers are primtive values, and primitive values are passed by value. This means the data is stored in a is copied to the list, not the point in memory a is held at.
Strings and arrays of any sort, however, are non-primitive.
To fix your code then, you need to pass 2 separate references to your list:
String[] pair1 = {"ChildA","Parent of ChildA"};
String[] pare2 = {"ChildB", "Parent of ChildB"};
//adding values to list
list.add(pair1);
list.add(pair2);
Edit:
You'd expressed concerns in comments about verbosity. First, I think your code isn't verbose. But if you're truly concerned about it here's a way to shorten it:
list.add(new String[]{"ChildA","Parent of ChildA"});
list.add(new String[]{"ChildB","Parent of ChildB"});
Because an ArrayList stores references, not objects. The reference pair always refers to the same object; you're simply adding that reference to your list twice.
Your string object array is overriding here. Your last change only will reflect in your string because list will store object's reference. If you want to get your assumed output create new objects every time before you set value.
I have many functions that take a global ArrayList as an argument, some of them don't make any change of this list, and others are need to remove some elements of this array while working, so i create a local tempArrays inside these function.
static ArrayList array1 = new ArrayList();
public fn1(ArrayList array1)
{
ArrayList tempArray1 = new ArrayList();
tempArray1 = array1;
tempArray1.remove(elemnt);
}
The problem is the deleted elements is deleted also from original arrayList array1, i don't know why? .
Thanks..
In line :
tempArray1 = array1;
You are making the tempArray1 variable to refer the same object of ArrayList to which array1 is referencing. Hence both are referencing the same object of ArrayList. Any change made in ArrayList object using any of the variables, would be reflected by both variables. So when you removing an element using:
tempArray1.remove(elemnt);
array1 is also reflecting that removal of element.
You should use:
ArrayList tempArray1 = new ArrayList(array1);
As specified in official documentation : ArrayList(Collection<? extends E> c) :
Constructs a list containing the elements of the specified collection,
in the order they are returned by the collection's iterator.
Parameters:
c - the collection whose elements are to be placed into this list
The problem is that declaring tempArray1 = array1; simply makes tempArray1 a reference to array1.
To create a true copy, call this:
ArrayList tempArray1 = new ArrayList(array1);
try to do the following
List tempList = new ArrayList(oldArrayList);
I think there are some fatures of Java that you have misunderstood:
When you declare a Java variable, it is a refenrence for an object, like a pointer in C/C++. It can be a referance to previously created object or you can create a new object to referance.
//Created a new object instance on heap
ArrayList tempArray1 = new ArrayList();
//Both tempArray1 and tempArray2 will point to same object in memory
ArrayList tempArray2 = tempArray1;
In your code you first creating a new ArrayList object referance tempArray1 and creating an a new object for it ArrayList tempArray1 = new ArrayList(); and than assigning an other referance to this referance by tempArray1 = array1;. So first object you have created has no reference that point it and will be deleted. Now both tempArray1 and tempArray2 are pointing the same oject.
In Java If you want to make a copy of an object you can use it's clone method if it has implemented the Clonable interface. Also look at this question for detailed answers about cloning How do I copy an object in Java?
So you want to make a copy of your array but you are doing it wrong.
The reason why the item is deleted from the original ArrayList is because, in Java, variables of reference types (arrays, Strings, and anything else which is a subclass of Object) hold references, not values. What that essentially means is that a variable of type ArrayList holds the memory address at which the data for the ArrayList is allocated. When you do tempArray1 = array1;, you're just giving tempArray1 the address of the same ArrayList. This all only applies to types that derive from Object in Java, which does happen to include String, if you didn't know. Primitive types (byte, short, int, long, char, float, double) are stored as values.
Now, onto your real problem; I must ask, why you don't just use the get(index) method to work with the item?
If you need to actually remove the element, use the copy constructor of ArrayList, like so:
ArrayList tempArray1 = new ArrayList(array1);
You are replacing the instance you created with the global one. Try with this:
ArrayList tempArray1 = new ArrayList(array1);
tempArray1.remove(elemnt);
You can also use the addAll(Collection c) Method
static ArrayList array1 = new ArrayList();
public fn1(ArrayList array1)
{
ArrayList tempArray1 = new ArrayList();
tempArray1.addAll(array1);
tempArray1.remove(elemnt);
}
A) tempArray1 is a variable that refers to the same instance as array1. To make a copy, use the copy constructor:
List tempArray1 = new ArrayList(tempArray1);
B) Remove the parameter from the method. There is no need to pass the list in - code in the method already has access to the list. In fact, by passing it in using a parameter with the same name, you are shadowing the original list - if a different list was passed in, you would be working with that instead of the list you think you're working with.
C) You should type your list, for example:
static ArrayList<String> array1 = new ArrayList<String>();
D) Always use the abstract class: change it to List:
static List<String> array1 = new ArrayList<String>();
E) A list is not an array, so don't call the variable "array1" - its misleading:
static List<String> list1 = new ArrayList<String>();
Please consider my question. final values cannot be changed in java.
private final List<Integer> list = new ArrayList<Integer>();
above list instantiation is of final. now i can add any elements.
after that can i assign list=null?
Please help me.
Thanks!
That means the variable list is final.
Which means you can not assign something else to it again.
Once you are done assign a value (reference) to it as follows:
private final List<Integer> list = new ArrayList<Integer>();
You can not do something as below again:
list = new ArrayList<Integer>(); //this is invalid because you are trying to assign something else the variable list
list.add(new Integer(123)); is this code valid?
It's perfectly valid. You are just adding an object to the ArrayList that variable list is referencing.
The usage of final keyword is restricting the variable list not the ArrayList object that it's referencing.
The new keyword in Java creates a new Object and returns its reference. Hence, in your code, the list variable stores the reference to the new list. Declaring it final means that the reference stored in list is final, and cannot be changed.
The actual list is still modifiable.
For your code and if you have this:
private final List<Integer> list = new ArrayList<Integer>();
This is possible:
list.add(3);
This is not allowed:
list = new ArrayList<Integer>();
The final keyword indicates that a variable can only be initialized once. It does not guarantee immutability of the object assigned to that variable. In other words, it says something about what a variable can refer to, but nothing about the contents of the referent.
I have some data structures, and I would like to use one as a temporary, and another as not temporary.
ArrayList<Object> myObject = new ArrayList<Object>();
ArrayList<Object> myTempObject = new ArrayList<Object>();
//fill myTempObject here
....
//make myObject contain the same values as myTempObject
myObject = myTempObject;
//free up memory by clearing myTempObject
myTempObject.clear();
now the problem with this of course is that myObject is really just pointing to myTempObject, and so once myTempObject is cleared, so is myObject.
How do I retain the values from myTempObject in myObject using java?
You can use such trick:
myObject = new ArrayList<Object>(myTempObject);
or use
myObject = (ArrayList<Object>)myTempObject.clone();
You can get some information about clone() method here
But you should remember, that all these ways will give you a copy of your List, not all of its elements. So if you change one of the elements in your copied List, it will also be changed in your original List.
originalArrayList.addAll(copyArrayList);
Please Note: When using the addAll() method to copy, the contents of both the array lists (originalArrayList and copyArrayList) refer to the same objects or contents. So if you modify any one of them the other will also reflect the same change.
If you don't wan't this then you need to copy each element from the originalArrayList to the copyArrayList, like using a for or while loop.
There are no implicit copies made in java via the assignment operator. Variables contain a reference value (pointer) and when you use = you're only coping that value.
In order to preserve the contents of myTempObject you would need to make a copy of it.
This can be done by creating a new ArrayList using the constructor that takes another ArrayList:
ArrayList<Object> myObject = new ArrayList<Object>(myTempObject);
Edit: As Bohemian points out in the comments below, is this what you're asking? By doing the above, both ArrayLists (myTempObject and myObject) would contain references to the same objects. If you actually want a new list that contains new copies of the objects contained in myTempObject then you would need to make a copy of each individual object in the original ArrayList
Came across this while facing the same issue myself.
Saying arraylist1 = arraylist2 sets them both to point at the same place so if you alter either the data alters and thus both lists always stay the same.
To copy values into an independent list I just used foreach to copy the contents:
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
fill list1 in whatever way you currently are.
foreach(<type> obj in list1)
{
list2.Add(obj);
}
Supopose you want to copy oldList into a new ArrayList object called newList
ArrayList<Object> newList = new ArrayList<>() ;
for (int i = 0 ; i<oldList.size();i++){
newList.add(oldList.get(i)) ;
}
These two lists are indepedant, changes to one are not reflected to the other one.
Lets try the example
ArrayList<String> firstArrayList = new ArrayList<>();
firstArrayList.add("One");
firstArrayList.add("Two");
firstArrayList.add("Three");
firstArrayList.add("Four");
firstArrayList.add("Five");
firstArrayList.add("Six");
//copy array list content into another array list
ArrayList<String> secondArrayList=new ArrayList<>();
secondArrayList.addAll(firstArrayList);
//print all the content of array list
Iterator itr = secondArrayList.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}
In print output as below
One
Two
Three
Four
Five
Six
We can also do by using clone() method for which is used to create exact copy
for that try you can try as like
**ArrayList<String>secondArrayList = (ArrayList<String>) firstArrayList.clone();**
And then print by using iterator
**Iterator itr = secondArrayList.iterator();
while (itr.hasNext()) {
System.out.println(itr.next());
}**
You need to clone() the individual object. Constructor and other methods perform shallow copy. You may try Collections.copy method.
Straightforward way to make deep copy of original list is to add all element from one list to another list.
ArrayList<Object> originalList = new ArrayList<Object>();
ArrayList<Object> duplicateList = new ArrayList<Object>();
for(Object o : originalList) {
duplicateList.add(o);
}
Now If you make any changes to originalList it will not impact duplicateList.
to copy one list into the other list, u can use the method called
Collection.copy(myObject myTempObject).now after executing these line of code u can see all the list values in the myObject.
Copy of one list into second is quite simple , you can do that as below:-
ArrayList<List1> list1= new ArrayList<>();
ArrayList<List1> list2= new ArrayList<>();
//this will your copy your list1 into list2
list2.addAll(list1);
Here is a workaround to copy all the objects from one arrayList to another:
ArrayList<Object> myObject = new ArrayList<Object>();
ArrayList<Object> myTempObject = new ArrayList<Object>();
myObject.addAll(myTempObject.subList(0, myTempObject.size()));
subList is intended to return a List with a range of data. so you can copy the whole arrayList or part of it.
Suppose you have two arraylist of String type .
Like
ArrayList<String> firstArrayList ;//This array list is not having any data.
ArrayList<String> secondArrayList = new ArrayList<>();//Having some data.
Now we have to copy the data of second array to first arraylist like this,
firstArrayList = new ArrayList<>(secondArrayList );
Done!!
The simplest way is:
ArrayList<Object> myObject = new ArrayList<Object>();
// fill up data here
ArrayList<Object> myTempObject = new ArrayList(myObject);