Copying an object in Java without affecting the original through the copy constructor

I am trying to copy an object, which will then be modified without changing the original object.

I found this solution , and, in my opinion, the copy constructor would be the best approach - from my understanding it would give me a deep copy (a completely separate object from the original).

So, I tried this. However, I noticed that when the following code is executed, it executes all the previous objects from which it was copied. When I call surveyCopy.take() , which will change the values ​​inside Survey , it will also change the values ​​inside the selected Survey .

 public class MainDriver { ... //Code that is supposed to create the copy case "11": selectedSurvey = retrieveBlankSurvey(currentSurveys); Survey surveyCopy = new Survey(selectedSurvey); surveyCopy.take(consoleIO); currentSurveys.add(surveyCopy); break; } 

and here is the code for my copy constructor:

 public class Survey implements Serializable { ArrayList<Question> questionList; int numQuestions; String taker; String surveyName; boolean isTaken; //Copy constructor public Survey(Survey incoming) { this.taker = incoming.getTaker(); this.numQuestions = incoming.getNumQuestions(); this.questionList = incoming.getQuestionList(); this.surveyName = incoming.getSurveyName(); this.isTaken = incoming.isTaken(); } } 

So what is the problem? Doesn't such a constructor work? I'm not wrong?

+4
source share
3 answers

This is the problem in your copy constructor:

 this.questionList = incoming.getQuestionList(); 

This is just copying a link to a list. Both objects will still refer to the same object.

You can use:

 this.questionList = new ArrayList<Question>(incoming.getQuestionList()); 

to create a copy of the original list - but this is still not enough if Question itself modifies. In this case, you need to create a copy of each Question object to achieve complete isolation.

Your other fields are fine, as they are either primitives or String references (which is immutable, allowing you to exchange links safely).

+13
source

it

 this.questionList = incoming.getQuestionList(); 

most likely copies the link to the source list (I say, probably, since it is possible that getQuestionList() gives you a protective copy). You may need to create a new copy of this list. And, possibly, the contained Question objects. And perhaps all that they refer to.

This is a problem with deep copies. To do this reliably, you need to copy all mutable objects. Please note: if the object is immutable (for example, strings), then they cannot be changed and therefore you can refer to the originals, confident that they will not be changed. The same applies to primitives. One good reason to encourage immutability in your code base.

If you cannot create an immutable class, write your class so that it makes protective copies. that is, when a client requests it for a collection, he must make a copy and return it. Otherwise, your supposedly well-intentioned customers may change your internal state (inadvertently or otherwise).

+8
source

The problem with creating deep copies is that everything that is not a primitive type is copied by reference, unless you also use a specific deep copy constructor on it.

In your particular case, you have no problem with variable bool , int or a String , because you pass them by value (in fact, String is passed by reference, but it is not changed, so there is no problem), but you pass ArrayList<Question> questionList . When you do

 this.object = incoming.object 

you just copy the link. Thus, both variables point to the same object in memory , so you are not deep copying it. You must create another instance of the object with the same internal values, then you will be sure, for example this.object = new YourObject(incoming.object) .

The mind, which usually means that your class is more complicated in the composition tree, you will need to go into variables more until you copy them.

+5
source

All Articles