Saturday, April 28, 2012

Pass by Value Vs Pass by Reference


Most methods passed arguments when they are called. An argument may be a constant or a variable. For example in the expression: Math.sqrt(x); The variable x is passed here.

Pass by Reference means the passing the address itself rather than passing the value and pass by value means passing a copy of the value as an argument.

This is simple enough, however there is an important but simple principle at work here. If a variable is passed, the method receives a copy of the variable's value. The value of the original variable cannot be changed within the method. This seems reasonable because the method only has a copy of the value; it does not have access to the original variable. This process is called pass by value.

However, if the variable passed is an object, then the effect is different. We often say things like, "this methodreturns an object ...", or "this method is passed an object as an argument ..." But this is not quite true, more precisely, we should say, something like "this method returns a reference to an object ..." or "this method is passed a reference to an object as an argument ..."

Generally, objects are never passed to methods or returned by methods. It is always "a reference to an object" that is passed or returned. In general, pass by value refers to passing a constant or a variable holding a primitivedata type to a method, and pass by reference refers to passing an object variable to a method. In both cases a copy of the variable is passed to the method. It is a copy of the "value" for a primitive data type variable; it is a copy of the "reference" for an object variable. So, a method receiving an object variable as an argument receives a copy of the reference to the original object.

Here's the clincher: If the method uses that reference to make changes to the object, then the original object is changed. This is reasonable because both the original reference and the copy of the reference "refer to" to same thing — the original object. There is one exception: strings. Since String objects are immutable in Java, a method that is passed a reference to a String object cannot change the original object.

To understand pass by reference lets see the sample program below:

public class TestPassByReference {
         public static void main(String[] args) {
                // declare and initialize variables and objects
                int i = 25;
                String s = "Java is fun!";
                StringBuffer sb = new StringBuffer("Hello, world");

                // print variable i and objects s and sb
                System.out.println(i);     // print it (1)
                System.out.println(s);    // print it (2)
                System.out.println(sb);  // print it (3)

                // attempt to change i, s, and sb using methods
                iMethod(i);
                sMethod(s);
                sbMethod(sb);

                 // print variable i and objects s and sb (again)
                 System.out.println(i);    // print it (7)
                 System.out.println(s);   // print it (8)
                 System.out.println(sb); // print it (9)

         }

         public static void iMethod(int iTest) {
                iTest = 9;                          // change it
                System.out.println(iTest); // print it (4)
                return;
         }

         public static void sMethod(String sTest) {
                sTest = sTest.substring(8, 11); // change it
                System.out.println(sTest);        // print it (5)
                return;
         }

         public static void sbMethod(StringBuffer sbTest) {
                sbTest = sbTest.insert(7, "Java "); // change it
                System.out.println(sbTest);            // print it (6)
                return;
          }
}

Output of the program :

25
Java is fun!
Hello, world
9
fun
Hello, Java world
25
Java is fun!
Hello, Java world


TestPassByReference begins by declaring and initializing three variables: an int variable named i, a String object variable named s, and a StringBuffer object variable named sb. The values are then printed. Then, each variable is passed as an argument to a method. Within each method, the copy of the variable exists as a local variable. The value of the variable — or the value of the object referred to by the variable, in the case of the String and StringBuffer object variables — is changed and printed within each method. The print statements are numbered to show the order of printing. Back in the main() method, the three values are printed again. Have a look at the output and see if it is consistent with our previous discussion.

The pass-by-reference concept is illustrated by the object variables sb and sbTest. In the main() method, a StringBuffer object is instantiated and initialized with "Hello, world" and a reference to it is assigned to the StringBuffer object variable sb.

igure 1 the memory assignments for the object and the object variable are illustrated. This corresponds to the state of the sb and sbTest variables just after line 8 in the code snippet. In the code snippet, the sbMethod() method is called with sb as an argument. Within the method, a copy of sb exists as a local variable named sbTest. The memory assignments just after the sbMethod() begins execution are shown in Figure 1b. Note that sb and sbTest refer to the same object.
Memory assignments for call-by-reference
Figure1. Memory assignments for call-by-reference example (StringBuffer objects)

In the sbMethod, the object is modified using the insert() method of the StringBuffer class. The method is called through the instance variable sbTest. The memory assignments just after insert() executes are shown in Figure 1c. After the sbMethod() finishes execution, control passes back to the main() method and sbTest ceases to exist. The memory assignments just after line sbMethod(sb) in the code snippet are shown in Figure 1d. You can that the original object has changed, and that the original object variable, sb, now refers to the updated object. This is a typical example of “pass by reference”. It demonstrates that methods can change the objects instantiated in other methods when they pass a reference to the object as an argument.

The String class is an exception in pass by reference. As Strings are immutable objects in java i.e. once instantiated the string objects cannot be changed. To understand this concept lets see figure 2.
 Memory assignments for call-by-reference
Figure2: Memory assignments for call-by-reference example (String objects)

In the code snippet, the sMethod is passing “s” as an argument. In the method’s definition a copy of “s” exist as a local variable called “sTest”. The memory assignments just after the sMethod() begins execution are shown in Figure 2b. It should be noted that s & sTest refers to the same object. At this point, there is no difference in how memory was assigned for the String or StringBuffer objects. The substring() method of the String class is called to extract the string "fun" from the original string. The result is the instantiation of a new String object. A reference to the new object is assigned to sTest. The memory assignments just after the line sTest = sTest.substring(8, 11) is shown in Figure2c.

After the sMethod() finishes execution, control passes back to the main() method and sTest ceases to exist. The memory assignments just after the statement sMethod(s) in the code snippet are shown in Figure 2d. The important point to note here is that the original object did not change. The String object containing "fun" is now redundant and its space is eventually reclaimed.

For integer variables the memory assignments are shown in figure 3. When an integer variable is passed as an argument to a method, it is passed by value. In the test program, an integer variable named i is declared and initialized
with value 25 (see figure 3a).
Memory assignments for call-by-value
Figure3. Memory assignments for call-by-value example (int variables)

In the main() method the iMethod() is called with i as an argument. Within the method, a copy of i exists as a local variable named iTest. The memory assignments just after iMethod() begins execution are shown in Figure 3b. Note that i and iTest are distinct: They are two separate variables that happen to hold the same value.

In the iMethod() method, the variable iTest is re-assigned the value 9. The memory assignment is shown in Figure 3c. After the iMethod() finishes execution, control passes back to the main() method and iTest ceases to exist. The memory assignment is shown in Figure 3d. The important point to notice here is that the value of the original variable did not change.

No comments:

Post a Comment