Call by Reference versus Call by Value


Much ado is made over whether Java uses "call by reference" or "call by value." These classic software development phrases describe how a language manages the passing of arguments to functions (perhaps in C) or methods. The terminology (or people's interpretations of the terminology) is not necessarily important. What's important is that you understand how Java manages the passing of arguments.

Call by value means that the called function[10] makes a copy of an argument behind the scenes. Code in the function operates on the copy. The implication is that any changes made to the argument are discarded when the function completes execution. The reason is because changes are not actually made to the argument but to its local copy. The copy of the argument has only method scope.

[10] I use the term "function" in these general definitions to imply that this is not necessarily how Java does it.

Call by reference means that the function works on the same physical argument that was passed in. Any changes to the argument are retained.

Java is entirely call by value. If you pass an int to a method, the method operates on a copy of the int. If you pass an object reference to a method, the method operates on a copy of the referencenot a copy of the object itself. I'll demonstrate both of these statements in code.

Understanding call by value with respect to primitives is easy enough. Here's a test to show you how the method's copy of the primitive gets discarded.

 public void testCallByValuePrimitives() {    int count = 1;    increment(count);    assertEquals(1, count); } private void increment(int count) {    count++; } 

Even though the increment method changes the value of count, the change is to a local copy. The local copy disappears upon exit of the increment method. Code in testCallByValuePrimitives remains oblivious to any of these shenanigans.

Remember that a reference is a pointeran address of an object's location in memory. The called method copies this address, creating a new pointer that refers to the same memory location. If you assign a new memory address (i.e., a different object) to the reference within the called method, this new address is discarded when the method completes.

Code in the called method can send messages to the object pointed at by the reference. These message sends can effect permanent changes in the object.

In testCallByValueReferences, shown following this paragraph, code creates a customer with an ID of 1. The test then calls the method incrementId. The first line of code in incrementId grabs the existing ID from the customer, adds 1 to this number, and sets the sum back into the customer. The second line in incrementId creates a new Customer object and assigns its address to the customer argument reference. You don't want to do this![11] The assignment is discarded when incrementId completes. The test finally verifies that the customer ID is 2, not 22.

[11] You might consider declaring all your arguments as final. Attempts to assign to the argument will result in compile failure. My ingrained habits prevent me from doing this consistently.

 public void testCallByValueReferences() {    Customer customer = new Customer(1);    incrementId(customer);    assertEquals(2, customer.getId()); } private void incrementId(Customer customer) {    customer.setId(customer.getId() + 1);    customer = new Customer(22); // don't do this } class Customer {    private int id;    Customer(int id) {this.id = id; }    void setId(int id) {this.id = id; }    public int getId() {return id; } } 



Agile Java. Crafting Code with Test-Driven Development
Agile Javaв„ў: Crafting Code with Test-Driven Development
ISBN: 0131482394
EAN: 2147483647
Year: 2003
Pages: 391
Authors: Jeff Langr

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net