0

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.

Kṛṣṇa
  • 91
  • 1
  • 8

2 Answers2

2

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.

Community
  • 1
  • 1
DAXaholic
  • 33,312
  • 6
  • 76
  • 74
  • Forgot to mention that this is related to JAVA. Concept surely is the same. – Kṛṣṇa Jun 17 '16 at 12:44
  • In other words: the same object is placed is both lists, and changing that object will be seen in both lists. Maybe the object itself must be cloned, or on change a new object should replace the original object. – Joop Eggen Jun 17 '16 at 12:56
0

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()
Community
  • 1
  • 1
John Burger
  • 3,662
  • 1
  • 13
  • 23