参考变量的封装?

时间:2016-02-21 07:09:58

标签: java oop

这可能是一个常见的问题,但我找不到合适的解释。我想了解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)。

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

2 个答案:

答案 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()。 每当我们返回集合或数组时,总是返回只读表单。因此,对集合的修改不会影响对象的状态。