-1

I have a ArrayList collection 1 of Details type. I assign it to another collection 2 to perform manipulations on it so that it does not affect collection 1. But I see the collection 1 is affected since object is referenced. But I want to have a two different collection with different memory references - plz help me.

Details class -

public class Details implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    private boolean enabled;

    private int number;

    public Details() {

    }

    public Details(int number, boolean enabled) {
        this.enabled = enabled;
        this.number = number;
    }

    public int getNumber() {
        return number;
    }

    public void setNumber(int number) {
        this.number = number;
    }

    public boolean getEnabled() {
        return enabled;
    }

    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

}

Main class -

public static void main(String[] args) {

    List<Details> detailsList = new ArrayList<Details>();
    detailsList.add(new Details(10, false));
    detailsList.add(new Details(20, false));

    List<Details> newDetailsList = new ArrayList<Details>(detailsList);
    for(Details d : newDetailsList) {
        d.setEnabled(true);
        d.setNumber(50);
    }

    for(Details d : detailsList) {
        System.out.println("---" + d.getEnabled());
        System.out.println("---" + d.getNumber());
    }

}

Output -

---true
---50
---true
---50

I create a new collection newDetailsList from detailsList and modify it... I see the changes were applied to detailsList collection. How can I avoid that

kosa
  • 65,990
  • 13
  • 130
  • 167
Hari
  • 39
  • 6

3 Answers3

1

Collections hold references, copies of Collections hold the same References

A collection only holds references to the objects. A copy of a collection is just a new reference that holds the same references to the same objects.

This will never work unless you make a deep clone of all the objects in the collection.

Cloning is broken in Java

This is not a simple as just implements Clonable on the objects that you want to copy and there are lots of caveats to this and almost impossible to get correct, to the point of not even bothering except in very simple cases, especially if there are objects that you don't have the source for.

As such all the instance variables of your Details object have to be deep copied as well, as all its instance members, as well as theirs, as well as theirs, as well as theirs. And you have to avoid circular references while you are at it. Like I said, not as simple as it sounds.

Sometimes this is just not possible, especially with mutable objects. But there is a solution.

Idiomatic Solution

Make your Details object immutable, and create new instances from the original and set the new values you need when you construct the new instance.

public class Details 
{
    private final Boolean enabled;

    private final Integer number;

    public Details(@Nonnull final Integer number, @Nonnull Boolean enabled) 
    {
        this.enabled = enabled;
        this.number = number;
    }

    public int getNumber() { return number;}

    public boolean getEnabled() { return enabled; }
}

A good convenience factory method would be:

public static Details newDetailsFromOldDetails(@Nonnull final Details details, @Nullable Integer number, @Nullable Boolean enabled)
{
    final Integer n = number == null ? details.getNumber() : number;
    final Boolean e = flag == null ? details.getBoolean() : enabled;
    return new Details(n, e)
}
Community
  • 1
  • 1
  • Hi Jarrord, I am able to achieve it by deep copy(cloning) in the sample I provided. But cloning would be simply impossible for the object which I use in my application. Thanks a lot – Hari Feb 14 '14 at 16:25
  • @Hari that is kind of my point, **deep cloning** is a mess, making your objects `immutable` has many benefits and few to no drawbacks. –  Feb 14 '14 at 16:27
0

You copy the list, but you do not copy the items contained in the list. So if you modify the items in the copied collection, the change will still show up in the items within the original collection. You likely want a deep copy, which will entail creating a mechanism through which Details objects can be copied, and then adding copies of the original list's items to the new list. By contrast, using the copy constructor of ArrayList simply copies the references (i.e. shallow copy).

arshajii
  • 127,459
  • 24
  • 238
  • 287
-1

Clone each Object of Details type like below -

List<Details> newDetailsList = new ArrayList<Details>();
    for(Details t : detailsList) {
        newDetailsList.add(t.clone());
    }


public Details clone() {
    return new Details(this.number, this.enabled);
}

But this would not be possible for the object which I really use in my application.

Hari
  • 39
  • 6
  • `.clone()` [is not a public method](http://docs.oracle.com/javase/7/docs/api/java/lang/Object.html#clone())! And it is not the way to solve this problem. **Thus, this method performs a "shallow copy" of this object, not a "deep copy" operation. The class Object does not itself implement the interface Cloneable, so calling the clone method on an object whose class is Object will result in throwing an exception at run time.** –  Feb 15 '14 at 03:00