将对象的防御副本添加到哈希集

时间:2017-05-24 14:29:13

标签: java hashset defensive-programming defensive-copy

目前我有这段代码:

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;
 }
}   

感谢

2 个答案:

答案 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; }
}

如果学生更改姓名 - 这种情况经常发生?在您的系统中,您可能根本不需要对其进行建模 - 或者更改课程,您只需创建一个新学生并删除旧的,不正确的学生。