这可能是一个常见的问题,但我找不到合适的解释。我想了解encapsulation of reference variables
中的Java
。在下面的代码中:
class Special {
private StringBuilder s = new StringBuilder("bob");
StringBuilder getName() { return s; }
void printName() { System.out.println(s); }
}
public class TestSpecial {
public static void main (String[] args ) {
Special sp = new Special();
StringBuilder s2 = sp.getName();
s2.append("fred");
sp.printName();
}
}
输出: bobfred
起初我想创建我们的字段private
并提供getter
方法,它是一种很好的封装技术。但是当我仔细观察它时,我看到当我调用getName()
时,我确实会返回一个副本,就像Java一样。但是,我没有返回StringBuilder
对象的副本。我将返回一个指向唯一StringBuilder
对象的引用变量的副本。因此,在getName()
返回时,我有一个StringBuilder
对象和两个指向它的引用变量(s和s2)。
有什么技术可以很好地封装?代码示例预期的一个很好的解释:)。提前致谢。
答案 0 :(得分:5)
我能想到两种基本方法。
第一种是只返回不可变的值。然后呼叫者可以按照自己的意愿行事,而不会冒任何对象的完整性。在您的情况下,不可变类型将是String
:
class Special {
private String s = "bob";
String getName() { return s; }
void printName() { System.out.println(s); }
}
public class TestSpecial {
public static void main (String[] args ) {
Special sp = new Special();
String s2 = sp.getName();
s2 += "fred";
// Alternatively: StringBuilder s2 = new StringBuilder(sp.getName()).append("fred");
sp.printName(); // prints "bob"
}
}
注意:如果s
需要StringBuilder
,您可以返回s.toString()
。
另一种选择是返回一个可变值,但在你的getter中创建一个防御性副本。换句话说,返回带有重复数据的单独引用:
class Special {
private StringBuilder s = new StringBuilder("bob");
StringBuilder getName() { return new StringBuilder(s); } // return a copy of s
void printName() { System.out.println(s); }
}
public class TestSpecial {
public static void main (String[] args ) {
Special sp = new Special();
StringBuilder s2 = sp.getName();
s2.append("fred");
sp.printName(); // prints "bob"
}
}
答案 1 :(得分:1)
可以有多种方法将封装应用于可变对象。
提供复制构造函数(在上面的示例new StringBuilder(oldBuilder.toString())
public class Student{
private String name;
public Student(Student s){
this.name = s.name;
}
}
将原型模式与克隆方法结合使用。但是建议使用复制构造函数而不是克隆方法。
public Student implements Cloneable{
private int rollNo;
private String name;
public Student clone(){
Student s = (Student)super.clone();
s.name = this.name;
s.rollNo = this.rollNo;
return s;
}
}
public class Clazz{
private Map students= new HashMap();
public student getStudent(int rollNo){
Student s = students.get(rollNo);
return s.clone();
}
}
使用不可变形式的可变对象。例如Collections.unmodifiablecollection()
。
每当我们返回集合或数组时,总是返回只读表单。因此,对集合的修改不会影响对象的状态。