Reputation: 21976
Consider this code:
package Prova;
import java.util.ArrayList;
public class Prova
{
private ArrayList<String> people;
public Prova() {
people=new ArrayList<String> ();
}
public ArrayList<String> getPeople (){
return people;
}
public static void main(String[] args) {
Prova p=new Prova();
p.go();
}
public void go(){
ArrayList<String> temp=getPeople();
temp.add("jack");
System.out.print(getPeople());
}
}
It prints "jack".
Why? Doesn't this violate encapsulation? How to return it by value?
Upvotes: 2
Views: 21874
Reputation: 2962
Immutability is charming but as with making defensive copies, it can become expensive. The standard java collections just aren't designed as immutable data structures. So it would be nice if you can go like Johan Sjöberg suggests and do not expose the list at all.
But you should also consider why you need to enforce such a high level of encapsulation. Are you exposing your class as a public API? If not, if you know and control the clients of your class well, too much encapsulation can be just impractical. Remember that encapsulation/information hiding is less about security but more about presenting a concise and unambiguous API to a client.
Upvotes: 1
Reputation: 49197
You need to program defensively. There are a few alternatives to consider
public void addPerson(String personName) {
people.add(personName);
}
public List<String> getPeople {
return new ArrayList<String>(people);
}
As far as the why goes, it's as already explained by other posts. The value to the reference of the ArrayList
is passed (alas changing the value doesn't change the original reference). However the list itself contains modifiable references to its objects.
Upvotes: 10
Reputation: 1447
Java is essentially "pass by value", with a small but significant difference from what is usually meant by that i.e. it acutually is "pass by reference value".
So when you deal with Java Types(the Class citizens of the JVM, the non-primitive types), declaration like the following basically means that you will get a copy of the reference referenceToMyObject
of Type MyClass
, pointing to the same specific MyClass
Object instance in the JVM heap memory.
public class SomeClass {
private MyClass referenceToMyClassInstance = new MyClass("instanceId-1");
public MyClass getMyClassInstance() {
return referenceToMyClassInstance;
}
}
So in your example you basically get copy of reference pointing to the same ArrayList
instance and anyone who called getPeople()
will now be able to change the actual instance anyway he/she likes, possibly corrupting what should be encapsulated state.
So you should return a copy of the ArrayList or wrap it with unmodifiable Decorator Collections.unmodifiableList(people)
Upvotes: 0
Reputation: 3155
The getPeople() method is violating encapsulation here because it returns a reference to its private list instead of returning an immutable view or a copy. You could easily solve this by implementing this method as:
public List<String> getPeople() {
return Collections.unmodifiableList(people);
}
I recommend to have a look at Joshua Bloch's excellent book "Effective Java (2nd Edition)", "Item 39: Make defensive copies when needed".
Upvotes: 1
Reputation: 8261
Java is always pass by value:
So for your case, it is passing value of the reference object. Thus object reference.
Upvotes: 3