iaa*_*acp 4 java constructor copy object
我正在尝试复制一个Object,然后修改它,而不更改原始对象.
我找到了这个解决方案,似乎最好的方法是复制构造函数 - 从我的理解,这将给我一个深层复制(一个完全独立的对象与原始).
所以我试过了.但是,我注意到,当执行以下代码时,它会影响复制它的所有先前对象.当我调用时surveyCopy.take()
,它会改变其中的值Survey
,它也会改变selectedSurvey内部的值.
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;
}
Run Code Online (Sandbox Code Playgroud)
这是我的复制构造函数的代码:
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();
}
}
Run Code Online (Sandbox Code Playgroud)
究竟是什么问题呢?复制构造函数不是那样工作的吗?我编码错误的方式是什么?
Jon*_*eet 13
这是你的拷贝构造函数中的问题:
this.questionList = incoming.getQuestionList();
Run Code Online (Sandbox Code Playgroud)
那只是将引用复制到列表中.两个对象仍然会引用同一个对象.
您可以使用:
this.questionList = new ArrayList<Question>(incoming.getQuestionList());
Run Code Online (Sandbox Code Playgroud)
创建原始列表的副本 - 但如果它本身是可变的,这仍然不够好Question
.在这种情况下,您必须创建每个Question
对象的副本以实现完全隔离.
你的其他字段是可以的,因为它们是原语或引用String
(这是不可变的,允许你安全地共享引用).
这个
this.questionList = incoming.getQuestionList();
Run Code Online (Sandbox Code Playgroud)
最有可能复制对原始列表的引用(我说可能因为它可能getQuestionList()
会给你一个防御性的副本).您可能需要制作该列表的新副本.也许包含的Question
对象.也许他们引用的任何东西.
这是深拷贝的问题.为了可靠地执行此操作,您必须复制所有可变对象.请注意,如果一个对象是不可变的(例如字符串),那么它们就无法更改,因此您可以引用原始文件,确信它们不会被更改.这同样适用于原语.在代码库中鼓励不变性的一个很好的理由.
如果你不能创建一个不可变的类,写你的类,使它成为防御性副本.即当客户要求收集时,它应该复制并返回.否则你所谓善意的客户可能会改变你的内部状态(无意或无意).
创建深层副本时的问题是,除非您在其上使用特定的深层复制构造函数,否则通过引用复制非基本类型的所有内容.
在特定情况下,你有没有问题bool
,int
或者String
变量,因为你通过他们周围的值(实际上String
是按引用传递,但它是不可变的,所以没有问题),但你传递一个ArrayList<Question> questionList
.当你这样做
this.object = incoming.object
Run Code Online (Sandbox Code Playgroud)
你只需复制一个参考.因此,两个变量都指向内存中的同一个对象,因此您不会深入复制它.您必须创建具有相同内部值的对象的另一个实例,然后您将确定,例如this.object = new YourObject(incoming.object)
.
请注意,通常意味着在合成树中你的课程更复杂,你必须深入研究变量,直到你复制它们为止.