2

Maybe I'm just having a blackout but I cant find a feasible way to resolve my problem.

I have a singleton object of Class A containing an ArrayList<Item>. In Class C I need a specific Item of ArrayList<Item> (clone it). While ArrayList<Item> should be unchanged, I need to apply some modifications to the Item in Class C. I tried implementing Cloneable in Class Item like this:

public class Item implements Cloneable {

  private ArrayList<String> mSize = new ArrayList<>();

  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }

  public void modifySomething() {
  mSize.clear();
  }

}

Afterwards I wanted to get the Item like this:

class C {

 void foo() {

  Item item = null;

  try {
   item = (Item) A.getInstance().getItems().get(0).clone();
   item.modifySomething();
  } catch (CloneNotSupportedException e) {
   e.printStackTrace();
  }

 }
}

The problem is that the Item item also gets modified in the singleton object.

Q: Did i take the wrong approach to this? How can I get the desired behaviour?

bautista
  • 765
  • 10
  • 26
  • An MVCE would be very much appreciated. At this point there's no telling where the gotcha is. `Object.clone()` returns a shallow copy, so maybe that has something to do with it? – Robby Cornelissen Jun 05 '19 at 09:44
  • Perhaps you can post a [mcve] that includes what `modifysomething` actually does. If `Item` contains mutable objects, then your `clone()` method might be too simplistic. – khelwood Jun 05 '19 at 09:44
  • Also note that this has **nothing** to do with singletons or lists or what not. When trying to write up that minimal example, focus on just that: you have a class with a clone() method, and manipulating a cloned object somhow changes the original object. That alone is at the heart of your question, and anything else is noise that only adds complexity for no reason. – GhostCat Jun 05 '19 at 09:47
  • @Robby Cornelissen @khelwood : added some extra code, hope this clarifies my point. Yes, `Item` contains mutable objects. @GhostCat thanks for the hint. As I said, I'm kinda confused. – bautista Jun 05 '19 at 09:52
  • 2
    Yup, it's a shallow copy problem. You'll have to explicitly clone the `ArrayList`. – Robby Cornelissen Jun 05 '19 at 09:55
  • basically a duplicate of: https://stackoverflow.com/questions/869033/how-do-i-copy-an-object-in-java – GhostCat Jun 05 '19 at 10:18

2 Answers2

3

Here:

protected Object clone() throws CloneNotSupportedException {
  return super.clone();
}

That is basically a "no op". It does not magically copy the content of your list into a new one. And just for the record: for any method, it is really pointless to override, but to then only call the super method implementation. Then you could as well: just not override that method.

So, either use a different mechanism, or really overwrite that method, with custom content to create a new List. Otherwise your clone and the original Item object operate on the same list instance.

GhostCat
  • 137,827
  • 25
  • 176
  • 248
2

What happens is, the clone it is not a "deep" clone, you still have referencing the same:

private ArrayList<String> mSize = new ArrayList<>();

inside you Cloned object. It if was a cloned object with no Collection attributes, it would work fine for you.

Apache Commons Lang has SerializationUtils#clone, which performs a deep copy when all classes in the object graph implement the Serializable interface.

item = (Item) SerializationUtils.clone(A.getInstance().getItems().get(0));
Brother
  • 2,150
  • 1
  • 20
  • 24