目前我有这段代码:
public final class Tutor {
private String name;
private final Set<Student> tutees;
public Tutor(String name, Student[] students){
this.name = name;
tutees = new HashSet<Student>();
for (int i = 0; i<students.length; i++)
tutees.add(students[i]);
}
我正在尝试重写它(只是在纸上),以便它制作/添加学生的防御性副本,而不是直接将它们添加到hashset中,并且我想知道以下代码是否会这样做:
public final class Tutor {
private String name;
private final Set<Student> tutees;
public Tutor(String name, Student[] students){
this.name = name;
tutees = new HashSet<Student>();
for (int i = 0; i<students.length; i++)
tutees.add(students[i](students.getName(), students.getCourse());
}
学生代码(如果需要):
public class Student {
private String name;
private String course;
public Student(String name, String course){
this.name = name;
this.course = course;
}
public String getName() { return name; }
public String getCourse() { return course; }
public void setName(String name) {
this.name = name;
}
public void setCourse(String course){
this.course = course;
}
}
感谢
答案 0 :(得分:2)
你做得对,但有一些错误,因为你是在纸上写的。如果你将它重写到程序中,由于这行
,它将无法编译tutees.add(students[i](students.getName(), students.getCourse());
需要替换为
tutees.add(new Student(students[i].getName(), students[i].getCourse());
注意,您要添加新的Student
,但字段由现有引用初始化,这会导致浅层复制 - 对象不同但正在分享内容。但是,String
类是immutable
,这意味着每个修改字符串的方法都会创建带有应用修改的新字符串,旧字符串保持不变。因此,即使原始学生和它的副本共享内容,字符串修改也不会相互影响,因此我们可以说它就像防御副本。
Student original = new Student("name", "course");
Student copy = new Student(original.getName(), original.getCourse());
// does not change the name of the copy
String modifiedName = copy.getName().replaceAll("a", "b");
以下是真实防御性副本(深层复制)的示例:
Student deepCopy = new Student(
new String(original.getName()),
new String(original.getCourse())
);
出于效率原因,如果您知道自己正在使用immutable
的课程,请复制其参考资料。
答案 1 :(得分:1)
您已经确定了将可变学生加入Set
的问题是一个坏主意。一旦它出现在集合中,你就不想改变它,因为它违反了集合的合同。
创建副本会处理症状,但不会处理根本问题。问题是你的学生班是可变的。如果你使Student类不可变,你不需要担心复制,并且它将更不容易出错。
public class Student {
private String name;
private String course;
public Student(String name, String course){
this.name = name;
this.course = course;
}
public String getName() { return name; }
public String getCourse() { return course; }
}
如果学生更改姓名 - 这种情况经常发生?在您的系统中,您可能根本不需要对其进行建模 - 或者更改课程,您只需创建一个新学生并删除旧的,不正确的学生。