参考变量的封装?

Set*_*sak 4 java oop

这可能是一个常见的问题,但我找不到很好的解释.我想了解encapsulation of reference variablesJava.
在以下代码中:

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();
    }
}
Run Code Online (Sandbox Code Playgroud)

输出: bobfred

起初我认为制作我们的领域private并提供一种getter方法,这是一种很好的封装技术.但是当我仔细观察它时,我看到当我调用时getName(),我确实会返回一个副本,就像Java一样.但是,我没有返回该StringBuilder对象的副本.我正在返回一个指向唯一StringBuilder对象的引用变量的副本.所以,在getName()返回的点上,我有一个StringBuilder对象和两个指向它的引用变量(s和s2).

有什么技术可以很好地封装?代码示例预期的一个很好的解释:).提前致谢.

shm*_*sel 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"
    }
}
Run Code Online (Sandbox Code Playgroud)

注意:如果s需要是a 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"
    }
}
Run Code Online (Sandbox Code Playgroud)