Why modification in Arraylist copy, modifies the original? [duplicate] - java

This question already has answers here:
Copy of arraylist keeps getting modified to the values of the original
(4 answers)
Closed 6 years ago.
I am trying to copy the contents of an ArrayList to another and change the contents of copy. I don't want this to be reflected in the original.
I checked on SO and made changes accordingly, still the same issue. Can someone help? I am sharing the code below:
private ArrayList<CustVoiceListObject> FilterApprovedWorkFromList() {
ArrayList<CustVoiceListObject> arrayListCopy = new ArrayList<>(arrayListCustVoice);
for(int i =0; i<arrayListCopy.get(position).getPackageArray().size();i++)
{
if(!arrayListCopy.get(position).getPackageArray().get(i).getPackageApproved().equals("Y"))
{
arrayListCopy.get(position).getPackageArray().remove(i);
i--;
}
}
return arrayListCopy;
}
While debugging, when it is about to return, I check the original arraylist arrayListCustVoice but this is also modified similar arrayListCopy
What am I missing?
UPDATE [Following the suggestions][This questions hence is not duplicate!]
This is my modified code:
private ArrayList<CustVoiceListObject> FilterApprovedWorkFromList() {
ArrayList<CustVoiceListObject> arrayListCopy = (ArrayList<CustVoiceListObject>) arrayListCustVoice.clone();
for(int i =0; i<arrayListCopy.get(position).getPackageArray().size();i++)
{
if(!arrayListCopy.get(position).getPackageArray().get(i).getPackageApproved().equals("Y"))
{
arrayListCopy.get(position).getPackageArray().remove(i);
i--;
}
}
return arrayListCopy;
}
In fact I have implemented Cloneable to my original class, still I am facing the same problem.
Update 2 [Research Conclusion]
I came across this link
In my case, there are 2 classes. The 2nd is subset of first. Pasting below:
public class CustVoiceListObject implements Cloneable {
private String txtSource, txtCustComment, txtCustOk, txtRepeat;
private int numberOfPackages, complaintSerial;
private ArrayList<CustomerVoicePackageListObject> packageArray;
private Double totalAmount;
//getters & setters & constructors
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
Class 2:
public class CustomerVoicePackageListObject implements Cloneable {
public String packageCategory;
public String packageName;
public String partUsageFlag;
public String laborUsageFlag;
public String status;
public String isApproved;
//getters & setters & constructors
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
The .clone() must link to the clone() of the CLASS, not elsewhere. And if it correctly does, it will provoke for taking measure to address the exception as per my implementing the clone() in each individual class.
So this is what I did, modified that for loop to this:
private CustVoiceListObject FilterApprovedWorkFromList() {
//Observe the change here. It's no more ArrayList, it's Class type
CustVoiceListObject arrayListCopy = null;
try {
arrayListCopy = (CustVoiceListObject) arrayListCustVoice.get(position).clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
for(int i =0; i<arrayListCopy.getPackageArray().size();i++)
{
if(!arrayListCopy.getPackageArray().get(i).getPackageApproved().equals("Y"))
{
arrayListCopy.getPackageArray().remove(i); //this is ArrayList<ClassType>. Nested class objects.
arrayListCopy.setTxtCustOk("OKOK"); //within the class
i--;
}
}
return arrayListCopy;
}
The result was the changes within the packageArray reflected in both (failure) BUT, changes in txtCustOk within the basic class, changed in copy, not in original (success). That means, problem is in cloning with ArrayList
So deep cloning requires satisfaction of following rules:
1.No need to separately copy primitives.
2.All the member classes in original class should support cloning and in clone method of original class in context should call
super.clone() on all member classes.
3.If any member class does not support cloning then in clone method, one must create a new instance of that member class and copy all its
attributes one by one to new member class object. This new member
class object will be set in cloned object.
So my aim is to get rid of ArrayList and shift those elements to this class. This is painful. Looking for an easy alternative.

The problem is that your elements of the original ArrayList are reference values so you just copy the references to those objects but not the objects themselves (which seem to be another kind of arrays).
Have a look at this question which essentially deals with the same kind of problem.

The copy operation copied the original list - but not the elements of the list.
That is, if oldList had the following Person objects:
oldList: John, Jane, Jude, Joe
And you copied oldList to newList:
oldList: John, Jane, Jude, Joe
newList: John, Jane, Jude, Joe
And then deleted John from newList:
oldList: John, Jane, Jude, Joe
newList: Jane, Jude, Joe
you can see that they are two distinct lists. But you're not changing the lists, you're changing the objects inside the list. If Joe's name got changed to Jim, you'd have:
oldList: John, Jane, Jude, Jim
newList: Jane, Jude, Jim
You have only done what is called a "shallow" copy. You want to do a "deep" copy, as shown here.
Edit (to "Update 2" in question)
Your research didn't go far enough, I'm afraid. In your (new) Class 1:
public class CustVoiceListObject implements Cloneable {
// ints, Doubles, Strings
private ArrayList<CustomerVoicePackageListObject> packageArray;
//getters & setters & constructors
#Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
you simply returned super.clone() - letting Java do all the work for you. This basically does the shallow copy that's causing all your problems! You might as well not have made the object ICloneable. What you missed was that ints, Doubles and even Strings already copy successfully, so you don't need to clone them. But ArrayLists don't clone, so you need to help it along:
#Override
protected Object clone() throws CloneNotSupportedException {
// First copy the easy stuff
CustomerVoiceListObject cvlo = (CustomerVoiceListObject)super.clone();
cvlo.packageArray = new ArrayList<CustomerVoicePackageListObject>(packageArray.size()); // Make sure it's the right size
for (CustomerVoicePackageListObject cvplo: packageArray) {
cvlo.packageArray.add(cvplo.clone());
} // for
return cvlo;
} // clone()

Related

Is it okay for a class to have a field of its own type

I did the following, i got a stackoverflow error after some time, and I understand why it was.
public class Cat {
String name="default name";
Cat insideCat;
public Cat(){
System.out.println("Cat constructor");
insideCat = new Cat();
}
}
But what if I don't create a new Cat object within the constructor, but take a parameter of Cat type and assign it to the insideCat field.
public class Cat {
String name="default name";
Cat insideCat;
public Cat(Cat insideCat){
System.out.println("Cat constructor");
this.insideCat = insideCat;
}
}
I am just playing around with the code, just trying to find out what Java can do and cannot. In the second code, everything looked normal, until I started to test this class. I need a Cat object to create a Cat object (and to create this Cat object I need another Cat object...and it goes on). So technically I cannot test this class.
So my question is WHY does java allow to create an instance variable of its own type? I guess the whole purpose of a constructor is to initialize it's instance variables. So either I have to create a new object to initialize the insideCat or else I have to take Cat object from outside. Both doesn't seem to work.
What am I missing here. Is there any occurrence where instance variables of its own types can become useful, and can be used without any problem? Is it bad OOP practice to come up with classes like this?
Classes like this exist all the time.
Consider linked lists or trees, e.g.,
class ListNode {
ListNode next;
// Etc.
}
class TreeNode {
TreeNode left;
TreeNode right;
// Etc.
}
You wouldn't initialize the "child" objects in the constructor, you'd add them later.
In your example you'd need to have a method that created the insideCat at a later time. In general you wouldn't create child objects that had the exact same state, there'd be something to differentiate them either at construction time, in which case you could have a "oh god stop creating these now" condition, or while they were being added, e.g., you'd add them via a method and not in a constructor.
There is nothing wrong in having an instance member of same class.
an Employee has a manager and the manager is also an Employee
public class Employee{
private Employee manager;
//getters setters and constructor
}
There are many examples of self referencing data structures that are valid. Think of a LinkedList. Each LinkNode has a data field, and a pointer to the next LinkNode.
class LinkNode {
int data;
LinkNode nextLink;
public LinkNode(int d1) {
data = d1;
nextLink = null;
}
...
}
class LinkedList {
private LinkNode first;
...
}
Your StackOverflow problem stems from the fact that creating an instead of X requires the creation of another X, ad-infinitum.
Just think of your Cat example. Why would instantiating a Cat require of all things...another Cat!
There can be multiple constructors. Thus, you can have another constructor
public Cat(){...}
That would allow you to create an inside Cat. Afterwards you could create another Cat that contains the inside Cat. Obviously, the design might not be great here, depending on your needs. Dave Newton's answer about linked list is a great real world example of this usage.

How to deep copy [duplicate]

This question already has answers here:
How do I copy an object in Java?
(23 answers)
Closed 9 years ago.
I am having difficulties understanding the concept of "deep copy" in Java.
Assuming I had a class "myClass" with various parameters in it. I tried writing a method "copy" which was supposed to return a deep copy of such class as:
public myClass copy() {
myClass deepCopy = new myClass();
deepCopy.varA = varA;
deepCopy.varB = varB;
return deepCopy;
}
Can somebody confirm whether this is indeed "deep copying" or if I am doing something wrong?
Thanks!
If you don’t want to implement deep copy yourselves then you can go for serialization. It does implements deep copy implicitly and gracefully handling cyclic dependencies.
A nice article about Deep Copy, Clone and Shallow Copy can be found here.
Only If:
Class "myClass" only contains varA and varB.
Class "myClass" has no superclass.
Variables varA and varB are of an elementary type (ie. String, int, long, ....). Otherwise you'll have to apply the same copying process to them too.
In deep copy When the copied object contains some other object its references are copied recursively
see more at here
A deep copy occurs when an object is copied along with the objects to which it refers.
If suppose there is a MainObject1 of MainObject type having fields "field1" of int type, and "ContainObject1" of ContainObject type. When you do a deep copy of MainObject1, MainObject2 is created with "field3" containing the copied value of "field1" and "ContainObject2" containing the copied value of ContainObject1. So any changes made to ContainObject1 in MainObject1 will not be reflected in MainObject2.
In your implementation, if you are trying to simulate deep copy, then you should have only these two variables : varA and varB in your class of primitive type.
This would only be a deep copy if varA and VarB were primitive types. If they are reference types than your new object will point at the same instances of these classes as the original.
An easy way to implement deep copy is via serialization. Apache commons lang provides a utility method for this (SerializationUtils.clone( foo ) ).
It does however requires that all the objects are serializable.
If this is not the case for you XStream can be used for deep cloning with minimal development effort.
http://x-stream.github.io/
Observe output of following program.
1> See output without clone() method. Remove clone() method from following program. (example of shallow copy)
2> See output with clone() method. (Example Deep copy. See ArrayList object's output)
import java.util.ArrayList;
import java.util.List;
public class DeepCopy implements Cloneable {
private List<String> hobbiesList;
private int age;
private String name;
private float salary;
public static void main(String[] args) throws CloneNotSupportedException {
DeepCopy original = new DeepCopy();
original.name="AAA";
original.age=20;
original.salary=10000;
original.hobbiesList = new ArrayList<String>();
original.hobbiesList.add("Cricket");
original.hobbiesList.add("Movies");
original.hobbiesList.add("Guitar");
original.hobbiesList.add("Eating");
DeepCopy cloned = (DeepCopy) original.clone();
System.out.println("original:="+original);
System.out.println("cloned :="+cloned);
System.out.println("After adding two more hobbies in 'original' which untimately reflected in 'cloned'");
cloned.name="BBB";
cloned.age=27;
cloned.salary=18237;
cloned.hobbiesList.add("Trecking");
System.out.println("original :="+original);
System.out.println("cloned changed:="+cloned);
}
#Override
protected Object clone() throws CloneNotSupportedException {
DeepCopy clone = (DeepCopy)super.clone();
clone.hobbiesList = new ArrayList<String>(clone.hobbiesList);
return clone;
}
#Override
public String toString() {
return "My name is (String)"+name + " having age (int)"+age+". I earned (float)"+salary+" and hobbies are (ArrayList)"+hobbiesList;
}
}

Coding practise for initialising ArrayLists

I'm looking to improve my Java coding.
Can someone provide a link or an explanation on whether there's a code of practise to initialise ArrayLists and avoid the following problem:
-I have 6 ArrayList in one class, some are subsets of others. Because some are subsets of others I understand they share the same references through the "addAll()" and "add()" methods.
As a result, by attempting to change the elements in subsets I'm also altering the original sets because again - they share the same reference. My code is so messy that a few "get" calls results in 2 of my ArrayLists being reset.
I have researched this forum and google and I can't seem to find the relevant information I want. I only find simple examples of ArrayLists. I have noticed that there are a few ArrayList reference related questions on this forum so I think the answer to this question will benefit others in the future.
Can someone provide a link or an explanation on whether there's a code of practise to initialise ArrayLists and avoid the following problem:
There is no such a code of practice, or best practice or whatever on initializing ArrayLists.
The problem is basically that you need to understand the difference in Java between using a reference to an existing object, and creating a new object. And you need to then choose the appropriate one ... depending on what you are trying to do.
(Asking for "best practice" on this topic is like asking for "best practice" on whether you should use + or - operators ...)
Rather than Googling for "best practice" on this, I suggest you go back to your Java text book / tutorial / lecture notes and read up on:
what Java object references are
what object assignment means, and
what the new operator does.
And make sure that you really understand them. When you understand them you will be able to understand which to use to do what you are trying to do in your program.
addAll adds references to the objects in the ArrayList, not copies from objects. Id you want copies, you must iterate through the 1st ArrayList, and for every Object, call the "clone" function that will create a copy of the object, and add it to the new ArrayList.
Example:
public static void main(String[] args) {
ArrayList<Foo> A = new ArrayList<Foo>();
A.add(new Foo("foo1", 1));
A.add(new Foo("foo2", 2));
ArrayList<Foo> B = new ArrayList<Foo>();
System.out.println("Before: ");
System.out.println("A:");
for(Foo foo:A){
System.out.println(foo);
try {
B.add((Foo)foo.clone());
} catch (CloneNotSupportedException ex) {
//Never Gonna Happen
}
}
System.out.println("B:");
for(Foo foo:B){
System.out.println(foo);
}
A.remove(0);
System.out.println("After:");
System.out.println("A:");
for(Foo foo:A){
System.out.println(foo);
}
System.out.println("B:");
for(Foo foo:B){
System.out.println(foo);
}
}
public static class Foo{
private String Name;
private int Id;
public Foo(String Name, int Id) {
this.Name = Name;
this.Id = Id;
}
#Override
protected Object clone() throws CloneNotSupportedException {
return new Foo(Name,Id);
}
#Override
public String toString() {
return "Name: "+Name+", Id: "+Id;
}
}
This prints out:
Before:
A:
Name: foo1, Id: 1
Name: foo2, Id: 2
B:
Name: foo1, Id: 1
Name: foo2, Id: 2
After:
A:
Name: foo2, Id: 2
B:
Name: foo1, Id: 1
Name: foo2, Id: 2
If you deal with ArrayLists of classes you created, make sure they all have "clone" function overridden. For classes containing classes you also created, use the "clone" functions you created for the inner classes in the parent class "clone". And so on.

ArrayList references behavior

I am totally confused with ArrayList behavior. Wrote really long post, then realized no one is going to analyse huge code, so just core of the problem. Numbers are for convenience, but in my app these 0 and 24 are dynamic values.
ArrayList<VoipBlock> sortedBlocks = new ArrayList<VoipBlock>();
VoipBlock vb3 =new VoipBlock();
vb3=sortedBlocks.get(0);
vb3.setPacketNumber(24);
Essentially my final aim is to: modify and add back to arrayList as new value. However when I do that the guy at position 0 in ArrayList -> unsortedBlocks.get(0); replicates all the changes done to vb3 which of course is not what I want. I want vb3 acquire same values as VoipBlock inside of ArrayList, but I want it to be detached.
This is yet another case of passing by reference. I hate technical explanations - Java passes everything by value, BUT in some cases it passes references by values - this is same as saying not-oily oil. Please help.
It reminds me my start of learning JavaScript - I hated the language - until I watched proper materials at lynda.com - JavaScript Good Practices? - Diagrams killed me. It is the lazy description that turns us-youth away from brilliant technology, not the technology itself.
Please don't let it bother my stress and don't be in any way offended by me, it is just general complaining, maybe someone will look at it and make life better :-)
Thanks for Your time,
Desperately awaiting for help :-)
To achieve your objective you can use clone method. you have to override this method in VoipBlock class
Lets say VoipBlock is as follows
public class VoipBlock {
private int packetNumber;
private String type;
public int getPacketNumber() {
return packetNumber;
}
public String getType() {
return type;
}
public void setPacketNumber(int value) {
packetNumber = value;
}
public void setType(String value) {
type = value
}
public VoipBlock clone() {
VoipBlock clone = VoipBlock();
clone.setType(this.getType());
clone.setPacketNumber(this.getPacketNumber());
return clone;
}
}
So, using the same code you can do like as follows
ArrayList<VoipBlock> sortedBlocks = new ArrayList<VoipBlock>();
VoipBlock vb3 =new VoipBlock();
sortedBlocks.add(vb3);
vb3=sortedBlocks.get(0).clone();
vb3.setPacketNumber(24);
Note that upon calling clone method in above code segment, vb3 get assigned with a new VoipBlock instance. And already inserted VoipBlock to the array remains unchanged.
if you are looking to have kind of sample instances of VoipBlock instances which you later wanted to use in creating similar instances like them. check on immutability/mutability aspect of the code. check "Effective Java" by Joshua Blouch
The following will always copy the reference of b to a:
AnyClass a = ...;
AnyClass b = ...;
a = b;
What you want is probably to clone the object:
a = b.clone();
If I understand correctly, you're a bit unsure about how references and values work. I think the rule of thumb is that primitive types like int, char, boolean and maybe String are copied but Objects just have their reference passed.
The line vb3=sortedBlocks.get(0); completely replaces whatever vb3 used to be with the first thing in the ArrayList. And yes, it won't be a copy, it will be a reference to the same object in memory. So whatever you do will affect both of them. You need to either manually copy over all the information you need or to use a clone() or copy() function.
So for example, in your code, the line VoipBlock vb3 =new VoipBlock(); is a bit redundant because you're overwriting the new instance straight away.
What you really need here is to either use a copy constructor or declare VoipBlock to be Clonable so you can use the clone() method.
What you are interpreting as passing by reference is not actually passing by reference. Java objects are really pointers. Because of this you are passing the value of the pointer. So when you do:
vb3=sortedBlocks.get(0);
you are really assigning vb3 to point to the same locations in memory as sortedBlocks.get(0). Therefore when you manipulate vb3 properties through their setters, the result is seen in both.
If you want two separate pointers you need to use the new keyword or use the clone() method which does this under the hood.
An example to prove this is:
public class Person {
private String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
}
public class Main {
public void doSomething(Person p) {
p = new Person("Bob");
System.out.println(p.getName());
}
public static void main(String[] args) {
Person p = new Person("Billy");
System.out.println(p.getName());
doSomething(p);
System.out.println(p.getName());
}
}
Since Java is pass by value the output will be: Billy, Bob, Billy. If Java were pass by reference it would be Billy, Bob, Bob. If I did not do the new Person in the doSomething() method and instead used the setName() method I would end up with Billy, Bob, Bob also but this is due to the fact I'm now modifying off the same pointer not that I passed by reference as the example above proves that's not the case.

Copy an object in Java

I have an object that I need to copy in Java. I need to create a copy and run some tests on it without changing the original object itself.
I assumed that I needed to use the clone() method, but this is protected. Having done some research on the net, I can see that this can be overriden with a public method in my class. But I cannot find an explanation on how to do this. How could this be done?
Also, is this the best way of achieving what I need?
Another option by using Copy Constructor (from Java Practices):
public final class Galaxy {
public Galaxy (double aMass, String aName) {
fMass = aMass;
fName = aName;
}
/**
* Copy constructor.
*/
public Galaxy(Galaxy aGalaxy) {
this(aGalaxy.getMass(), aGalaxy.getName());
//no defensive copies are created here, since
//there are no mutable object fields (String is immutable)
}
/**
* Alternative style for a copy constructor, using a static newInstance
* method.
*/
public static Galaxy newInstance(Galaxy aGalaxy) {
return new Galaxy(aGalaxy.getMass(), aGalaxy.getName());
}
public double getMass() {
return fMass;
}
/**
* This is the only method which changes the state of a Galaxy
* object. If this method were removed, then a copy constructor
* would not be provided either, since immutable objects do not
* need a copy constructor.
*/
public void setMass( double aMass ){
fMass = aMass;
}
public String getName() {
return fName;
}
// PRIVATE /////
private double fMass;
private final String fName;
/**
* Test harness.
*/
public static void main (String... aArguments){
Galaxy m101 = new Galaxy(15.0, "M101");
Galaxy m101CopyOne = new Galaxy(m101);
m101CopyOne.setMass(25.0);
System.out.println("M101 mass: " + m101.getMass());
System.out.println("M101Copy mass: " + m101CopyOne.getMass());
Galaxy m101CopyTwo = Galaxy.newInstance(m101);
m101CopyTwo.setMass(35.0);
System.out.println("M101 mass: " + m101.getMass());
System.out.println("M101CopyTwo mass: " + m101CopyTwo.getMass());
}
}
There are two popular approaches. One is to provide a clone method as you mentioned, like so.
public class C implements Cloneable {
#Override public C clone() {
try {
final C result = (C) super.clone();
// copy fields that need to be copied here!
return result;
} catch (final CloneNotSupportedException ex) {
throw new AssertionError();
}
}
Pay attention to the "copy fields ... here!" part. The initial result is only a shallow copy, meaning that if there's a reference to an object, both the original and result will share the same object. For example, if C contains private int[] data you'd probably want to copy that.
...
final C result = (C) super.clone();
result.data = data.clone();
return result;
...
Note that you don't need to copy primitive fields, as their content is already copied, or immutable objects, as they can't change anyways.
The second approach is to provide a copy constructor.
public class C {
public C(final C c) {
// initialize this with c
}
}
Or a copy factory.
public class C {
public static C newInstance(final C c) {
return new C(c);
}
private C(final C c) {
// initialize this with c
}
}
Both approaches have their respective properties. clone is nice because its a method, so you don't have to know the exact type. In the end, you should always end up with a "perfect" copy. The copy constructor is nice because the caller has a chance to decide, as can be seen by the Java Collections.
final List c = ...
// Got c from somewhere else, could be anything.
// Maybe too slow for what we're trying to do?
final List myC = new ArrayList(c);
// myC is an ArrayList, with known properties
I recommend choosing either approach, whichever suits you better.
I'd use the other approaches, like reflective copying or immediate serializing/deserializing, in unit tests only. To me, they feel less appropriate for production code, mainly because of performance concerns.
Some options:
You can implement Cloneable for your object and put clone() method as public. See full explanation here: http://www.cafeaulait.org/course/week4/46.html
However, this produces a shallow copy and might be not something you want.
You can serialize and deserialize your object. You will need to implement Serializable interface for the object and all its fields.
You can use XStream to perform serialization via XML - you won't have to implement anything here.
For test code Serialization is maybe the safest answer, especially if the object is already Serializable try Apache Commons SerializationUtils for an implementation.
You can use org.apache.commons.lang3.SerializationUtils class for object cloning,
- Class should implement Serializable interface.
ClassName copyobject = SerializationUtils.clone(classobjectTocopy)
SerializationUtils.clone is also supported on Google App Engine instance
Joshua Bloch has some interesting things to say about cloneable. Depending on the size/construction of the object, I'd add a copy constructor to the object, or serialise/deserialise using one of the solutions mentioned above.
There are multiple ways to copy object in java(shallow or deep).
This Answer will help you.

Categories