将对象的防御副本添加到哈希集中
add a defensive copy of an object to a 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]);
}
我正在尝试重写它(只是在纸上),以便它 makes/adds 学生的防御副本而不是直接将它们添加到哈希集中,我想知道以下代码是否会这样做:
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;
}
}
谢谢
你做得对,但有一些错误,因为你是在纸上写的。如果你将它重写到程序中,它不会编译,由于这一行
tutees.add(students[i](students.getName(), students.getCourse());
需要替换为
tutees.add(new Student(students[i].getName(), students[i].getCourse());
请注意,您正在添加新的 Student
,但字段由 现有引用 初始化,这导致 浅拷贝 - 对象不同但共享内容。但是,String
class 是 immutable
,这意味着每个修改字符串的方法都会创建应用修改的新字符串,而旧字符串保持不变。所以即使原始学生和它的副本共享内容,字符串修改也不会相互影响,因此我们可以说它的行为类似于defensive-copy。
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
的 class,只需复制它们的引用即可。
您已经确定将可变学生放入 Set
是个坏主意的问题。您不想在集合中更改某些内容,因为它违反了集合的合同。
创建副本可以治标不治本。问题是您的 Student class 是可变的。如果你让你的 Student class 不可变,你就不需要担心复制,而且它会大大减少出错的可能性。
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 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]);
}
我正在尝试重写它(只是在纸上),以便它 makes/adds 学生的防御副本而不是直接将它们添加到哈希集中,我想知道以下代码是否会这样做:
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;
}
}
谢谢
你做得对,但有一些错误,因为你是在纸上写的。如果你将它重写到程序中,它不会编译,由于这一行
tutees.add(students[i](students.getName(), students.getCourse());
需要替换为
tutees.add(new Student(students[i].getName(), students[i].getCourse());
请注意,您正在添加新的 Student
,但字段由 现有引用 初始化,这导致 浅拷贝 - 对象不同但共享内容。但是,String
class 是 immutable
,这意味着每个修改字符串的方法都会创建应用修改的新字符串,而旧字符串保持不变。所以即使原始学生和它的副本共享内容,字符串修改也不会相互影响,因此我们可以说它的行为类似于defensive-copy。
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
的 class,只需复制它们的引用即可。
您已经确定将可变学生放入 Set
是个坏主意的问题。您不想在集合中更改某些内容,因为它违反了集合的合同。
创建副本可以治标不治本。问题是您的 Student class 是可变的。如果你让你的 Student class 不可变,你就不需要担心复制,而且它会大大减少出错的可能性。
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; }
}
如果学生更改姓名 - 这种情况多久发生一次?在您的系统中,您可能根本不需要对其建模 - 或者更改课程,您只需创建一个新学生并删除旧的、不正确的学生。