Ramy Al Zuhouri
Ramy Al Zuhouri

Reputation: 21976

Java returning references by value (or by reference)

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

Answers (5)

nansen
nansen

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

Johan Sj&#246;berg
Johan Sj&#246;berg

Reputation: 49197

You need to program defensively. There are a few alternatives to consider

  • Don't expose the list externally, expose methods to apply to the list instead, e.g.,
public void addPerson(String personName) {
    people.add(personName);
}
  • Return immutable objects or a copy of the object. E.g.,
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

Svilen
Svilen

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

Christian Schlichtherle
Christian Schlichtherle

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

Kowser
Kowser

Reputation: 8261

Java is always pass by value:

  1. For primitive type, it passes value directly.
  2. For object it passes value of the object reference.

So for your case, it is passing value of the reference object. Thus object reference.

Upvotes: 3

Related Questions