Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Encapsulation for Reference Variables?

Tags:

java

oop

It may be a common question but I couldn't find nice explanation for it. I am trying to understand the encapsulation of reference variables in Java.
In the below code:

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

Output: bobfred

At first I thought making our field private and providing a getter method, it's a good encapsulation technique. But when I took closer look on it, I saw that when I invoke getName(), I do in fact return a copy, just like Java always does. But, I am not returning a copy of the StringBuilder object. I am returning a copy of the reference variable that point to the one and only StringBuilder object. So, at the point that getName() returns, I have one StringBuilder object and two reference variables pointing to it ( s and s2).

What are the techniques to make it well encapsulated?? A good explanation with code example expected :) . Thanks in advance.

like image 874
Setu Kumar Basak Avatar asked Mar 14 '23 05:03

Setu Kumar Basak


1 Answers

There are two basic approaches I can think of.

The first is to only return immutable values. The caller can then do what he wants without risking the integrity of your object. In your case, the immutable type would be 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"
    }
}

Note: If s needs to be a StringBuilder, you can return s.toString().

The other option is to return a mutable value, but create a defensive copy in your getter. In other words, return a separate reference with duplicate data:

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"
    }
}
like image 74
shmosel Avatar answered Mar 24 '23 14:03

shmosel