I have a class and I am taking 2 instance form that like
List<MyClass> lstMyClassTemp;
List<MyClass> lstMyClass = new ArrayList<MyClass>();
after initial some value or change some thing in lstMyClass I will update the value of temp variable lstMyClassTemp by a function Update()
private void update1()
{
lstMyClassTemp = new ArrayList<MyClass>(lstMyClass);
}
now my problem is before I run update function when I change some value in the lstMyClass variable the value of lstMyClassTemp variable change immediately but it is not true
please let me know what part could made problem
Edit and Update
Thanks for your answers
your answers are useful in continue I get new error and problem when I am changing value in lstMyClass the value in the lstMyClassTemp change immediately which part can make a problem?
lstMyClassTemp = new ArrayList<MyClass>();
for (i = 0; i < lstMyClass.size; i++) {
lstMyClassTemp.add((MyClass)lstMyClass.get(i));
}
// ... other code ...
int rowIStr=0;
for (int j = 0; j < 5; j++) {
if(lstMyClassTemp .get(j).getTempName().equals(lstMyClassTemp.get(rowIStr).getName()))
lstMyClass.get(j).setName("Alex");
}
rowIStr++
// ... other code ...
update1();
The copy constructor of ArrayList only copies the direct contents of the ols ArrayList. It does not perform deep copies of the objects inside the ArrayList. Calling the copy contructor is the same as:
List<MyClass> lstMyClassTemp = new ArrayList<>();
for(MyClass m: lstMyClass){
lstMyClassTemp.add(m);
}
So the new ArrayList contains the same references to objects of the type MyClass as the old one, but still only references.
When you do this:
lstMyClassTemp= new ArrayList<MyClass>(lstMyClass);
you create an exact copy in lstMyClassTemp of the references to the objects in lstMyClass. So lstMyClassTemp and lstMyClass refer to different lists, but those two lists contain references to the same objects. Therefore, when you do:
lstMyClass.get(j).setName("Alex");
then you must remember that lstMyClass.get(j) returns a reference to the same object as lstMyClassTemp.get(j). Not a copy of the object, but the same actual object. Therefore, when you set the name of that object, you can see the changes by using both lstMyClass.get(j) and lstMyClassTemp.get(j), since they are the same object.
Your problem is that the creation method you used passes the reference to the variable instead of simply copying it. Since Java does not have pointers you will have to manually copy it yourself. Here's an example of how you might do that.
lstMyClassTemp = new ArrayList<MyClass>();
for (i = 0; i < lstMyClass.size; i++) {
lstMyClassTemp.add((MyClass)lstMyClass.get(i));
}
Finally I find a way that is easy and useful I am putting that here I hope it will be helpful for another time :)
public class MyClass implements Cloneable {
/** some method ***/
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
in main body code :
ArrayList<MyClass> lstMyClassTemp= new ArrayList<MyClass>();
ArrayList<MyClass> lstMyClass= new ArrayList<MyClass>();
for(MyClass m: lstMyClass){
lstMyClassTemp.add((MyClass)m.clone());
}
the main part is cloning
image description here
Related
i have a problem with taking the x from an ArrayList in a for.
Let me explain better with this code:
private ArrayList pointStorer = new ArrayList();
I first declare the ArrayList
public void mouseEntered(MouseEvent e){
for(int i = 0; i < pointStorer.size(); i++){
if(pointStorer.get(i).x <= e.getX()){
check = true;
}
}
}
Then when i try to pass the ArrayList and for every element get the x, it doesn't work, Java says that 'cannot find simbol' (the x).
Thank you in advance for your help.
When you get an element from your pointStorer you need to cast it to Point (or whatever class you are using), otherwise the program will not know its type and it will not know it has an x field.
But it would be better to explicitly define the array type, like this:
private List<Point> pointStorer = new ArrayList<Point>();
this way when you use get it will directly return a Point object and you would not have to cast it to access its fields.
Java think you have an ArrayList of Object.
You should give a type parameter like: ArrayList<Point> or other type with field x.
I feel I'm missing something basic in references VS values.In the following code, getRecentProduct is returning a reference to the list.
public class ProductMapWrapper {
Map<String, List<ProductInformation>> productMap = new HashMap<String, List<ProductInformation>>();
public void putObject(ProductInformation productInfo, String key){
List<ProductInformation> productInfoList = productMap.get(key);
if (null == productInfoList)
productInfoList = new ArrayList<ProductInformation>();
productInfoList.add(productInfo);
productMap.put(key, productInfoList);
}
public ProductInformation getRecentProduct(String key){
List<ProductInformation> productInfoList = productMap.get(key);
productInfoList.get(0); //returns reference
// the following is also returning reference
List<ProductInformation> productinfoListCopy = new ArrayList<ProductInformation>(productInfoList);
return productinfoListCopy.get(0);
}
}
// main function
ProductInformation productInfo = new ProductInformation();
productInfo.setProdID("2323");
ProductMapWrapper mapWrapper = new ProductMapWrapper();
mapWrapper.putObject(productInfo, "MEDICAL");
ProductInformation getObj = mapWrapper.getRecentProduct("MEDICAL");
System.out.println(getObj.getProdID());
ProductInformation getObj1 = mapWrapper.getRecentProduct("MEDICAL");
getObj1.setProdID("test");
System.out.println(getObj.getProdID()); // prints test
I followed different SO answers and mostly it has been suggested to use the following, but this is also returning reference.
List<ProductInformation> productinfoListCopy = new ArrayList<ProductInformation>(productInfoList);
return productinfoListCopy.get(0);
Clone is working for me. But I wanted to know where I'm missing. Can someone help?
The code you're using creates a copy of the list, but it's a "shallow copy". That means that it's a different list, but it's still referencing the same objects. And so if you get the first element of either list, you're getting a reference to the same object.
What you're trying to achieve is a "deep copy". You'll find a lot of information on the topic out there - here's an example question - it deals with arrays rather than lists but it's the same principle, and hopefully it's some useful reading Deep copy of an object array
I am not sure if I am doing some silly mistake, What I am trying to achieve is I have JSON list and I want to convert them into multiple objects depending on variable argument passed to function.
Unit u1= new Unit();
User us = new User();
//calling funtion
StaticUtil.MagicJsonMapper(list, u1,us);
System.out.println(u1.getUnitName()); //place -1 unitName is null after function call
Inside static class I have create a function
#SuppressWarnings("rawtypes")
public static void MagicJsonMapper(List list,Object... objects){
if(list.size()!= objects.length){
//TODO
System.out.println("parame`ter mismatch");
return;
}
int i=0;
ObjectMapper mapper = new ObjectMapper();
for(Object object : objects){
if(list.get(i) instanceof List){
MagicJsonMapper((List)list.get(i),object);
}
else{
objects[i] = mapper.convertValue(list.get(i), object.getClass());
}
i++;
}
//place -2 "objects" contains proper value of unitname
}
The issue is I am still not getting proper value in parameter after finished running this method. It means argument values are not retained as in contrast of normal java behaviour, is it something to do with variable argument.
Just for clarity I debugged the code and values are proper at the end of the function.
The objects array is created during the function call and discarded afterwards. If you need to access the values from the array after the call, you need to create the array explicitly.
I am a little confused as to how my Java program is allocating memory. Below is a typical situation in my program. I have an object created on the Heap inside of a class which I pass to other functions inside of other classes.
public class A {
private List<Integer> list = new ArrayList<Integer>();
public A() {
for(int i = 0; i < 100; i++)
list.add(i);
}
public void foo() {
B b = new B();
b.bar(this.list);
}
}
public class B {
A a = new A();
public int bar(List<Integer> list) {
list.add(-1);
return list.size();
}
public int getSize() {
List<Integer> list = a.list;
return a.size();
}
}
My question(s) are about how the memory is used. When A's list gets passed to B.bar(), does the memory get copied? Java is pass-by-value so I assumed the B.bar() function now contains a copy of the list which is also allocated on the heap? Or does it duplicate the list and put it on the stack? Or is the list duplicated at all? Similarly what applies to these memory questions inside of B.getSize()?
It's probably clearer to say that in Java, object references are passed by value.
So B gets a copy of the reference (which is a value) to the List, but not a copy of the List itself.
You can easily prove this to yourself by getting B to modify the List (by adding or removing something), and observing that A's List also changes (i.e. it is the same List).
However, if you change B's reference to the List (by creating and assigning a new List to it), A's reference is unchanged.
Java is pass-by-value, but the value of an expression or variable is always either a primitive or a reference. A reference, in turn, is either null or a pointer to some object.
In your case: private List<Integer> list = new ArrayList<Integer>(); declares list as having a reference type, and makes its value a pointer to a newly allocated ArrayList object.
When you use list as an actual argument, for example on the b.bar(this.list); call, the formal argument list in b.bar is initialized with a copy of that pointer. That is, bar's formal argument points to the same ArrayList object as A created. The ArrayList object is not copied.
Java is pass-by-value, dammit!
However, you only ever have access to references to Objects. In that sense, you are passing Object references by value.
I wish to confirm which scenario will cause a Garbage Collection on the object myObj:
Scenario 1
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
}
Scenario 2
ArrayList arList = new ArrayList();
while(someCondition)
{
myObj = new MyObect(); // a custom object
arList.add(myObj);
myObj=null;
}
Does explicitly setting an object as null improves garbage collection behavior or will be it same when I reset the object using the new constructor ?
You don't specify the scope of myObj and its important. If its a local variable it almost certainly doesn't matter. If its an instance variable then that could be a long-lived and unnecessary reference in which case setting to null will be useful.
Update: given the updated information that myObj is local to the method, it will be of zero value to set it to null at the end of each iteration of the loop. Consider this example:
public void process(String text) {
String[] lines = text.split("\n");
List<MyObject> list = new ArrayList<MyObject>();
Object myObj;
for (String line : lines) {
myObj = new MyObject(line);
list.add(myObj);
// 1. set myObj = null here
}
list = null; // 2
// 3. do some other stuff
}
public class MyObject {
private final String line;
public MyObject(String line) {
this.line = line;
}
}
Now in this example, let's say that at step 3, it took a long time. Say 10 minutes. During that 10 minutes myObj is pointing to the last line processed. Doesn't sound like a problem? Well it could be. The way substrings work in Java is that they reference the original string. So if you do:
String s = ... // 100 megabytes
String s2 = s.substring(100, 101);
you're actually keeping the entire 100MB in memory because s2 references s.
So in the function I have above, myObj references a line which references the entire file. Changing step 1 to myObj = null; would actually help that because this reference is preventing the object being garbage collected.
Note: step 2 is important here because if you didn't nullify the list all the references would exist anyway.
You just need to think about how references work. An object won't be garbage collected while a reference to it exists. This means clearing long-lived references and keeping variables scoped as tightly as possible. The correct solution for the above is:
for (String line : lines) {
Object myObj = new MyObject(line);
...
}
and then myObj is scoped inside the loop so as soon as the loop ends or another iteration begins it has gone out of scope, which is much better.
Setting it to null will have no effect, since the object is still reachable via arList.
That is, your MyObect instances will live at least as long as arList.
EDIT: Based on your comment, it does sound like myObj is longer-lived. In that case, set it to null after the end of your loop.
I think that this is the root of your misunderstanding.
hmm.. but I don't wish to keep 2 copies of myObj , one in arList and one in the original variable. How can I flush myObj once I add it to arLsit ?
You do NOT "keep two copies of myObj". In your examples, there is only ever one "copy" of each MyObject instance created by the loop. The sequence is:
You create a MyObject instance, assigning its reference to myObj.
You add the reference to the instance to the ArrayList that arList refers to.
You assign null to the reference in myObj.
Note that adding the reference to the list does NOT create a copy of the MyObject instance. It simply means that that you have the reference in two places instead of
one. And when you assign the null you once again have the reference in just one place.
The other thing to note is that assigning null to something will never CAUSE the garbage collector to run. All it does is to (explicitly) remove a potential copy of a reference from consideration the next time the garbage collector is run.
Finally, if we assume that the scoping is as follows, then the line C will have no discernible effect ... unless either line A or line B triggers a garbage collection.
{
MyObject myObj;
ArrayList arList = new ArrayList();
while (someCondition) { // A
myObj = new MyObect(); // B
arList.add(myObj);
myObj = null; // C
}
}
Because it is in a while, myObj is always overwritten (the reference). So in Scenario 1 only one object (the last added in arList) will not be null.
It would be better if you declare it in the while statement:
while(someCondition)
{
MyObect myObj = new MyObect(); // a custom object
arList.add(myObj);
}