Skip to main content

skip to main content

developerWorks  >  Java technology  >

Pass-by-value semantics in Java applications

developerWorks
Document options

Document options requiring JavaScript are not displayed


Rate this page

Help us improve this content


Level: Introductory

Peter Haggar (haggar@us.ibm.com), Senior Software Engineer, IBM

02 Jun 2000

A few months ago, developerWorks posted some excerpts from my book, Practical Java, published by Addison-Wesley. I will initially use this column on developerWorks to answer some questions asked by readers and to respond to various comments about the excerpts.

The excerpt Understanding that parameters are passed by value and not by reference described the one and only parameter-passing mechanism in Java applications, pass by value. It was written to debunk the commonly held myth that Java applications pass parameters by reference, to avoid common programming mistakes that result from relying on pass-by-reference behavior.

Some of the feedback on this excerpt suggested that I was confusing the issue or was altogether wrong about it. Many of the readers who disagreed with me used the C++ language as an example. Therefore, in this column, I will use C++ and Java applications to further clarify the facts.

The key point

After reading all of the comments, it became clear that there is at least one major point of confusion. Some comments said that my excerpt is wrong because objects are passed by reference. It is true that objects are passed by reference; the excerpt was not contradicting that. The excerpt said that all parameters are passed by value -- a different argument. It is correct that you never pass an object in a Java application, only an object reference. Therefore, you are passing objects by reference. However, it is important to distinguish how parameters are passed, and that was the intent of the excerpt. The fact that a Java application passes objects by reference does not mean that a Java application passes parameters by reference. Parameters can be object references, and a Java application passes object references by value.



Back to top


Parameter passing in C++ and Java applications

Variables in Java applications can be one of two types: reference types or primitive types. Both types are handled the same way when passed as arguments to a method. Both are passed by value; neither is passed by reference. This is an important distinction as the subsequent code examples illustrate.

Before going further, it is important to define the terms pass by value and pass by reference. Pass by value means that when an argument is passed to a function, the function receives a copy of the original value. Therefore, if the function modifies the parameter, only the copy is changed and the original value remains unchanged. Pass by reference means that when an argument is passed to a function, the function receives the memory address of the original value, not a copy of the value. Therefore, if the function modifies the parameter, the original value in the calling code is changed.

Some of the confusion about parameter passing in Java applications originates from the fact that many programmers came to Java programming from C++ programming. C++ contains both non-reference types and reference types and passes them by value and by reference, respectively. The Java programming language has primitive types and object references, and therefore, it is logical to think that Java applications use pass by value for the primitive types and pass by reference for references, much like C++. After all, you might think if you are passing a reference, it must be pass by reference. It is tempting to believe this, and in fact it was my belief for some time, but it is not true.

In both C++ and Java applications, when a parameter to a function is not a reference, you pass a copy of the value (pass by value). The difference is with references. In C++ when a parameter to a function is a reference, you are passing the reference, or the memory address (pass by reference). In Java applications, when an object reference is a parameter to a method, you are passing a copy of the reference (pass by value), not the reference itself. Note that the calling method's object reference and the copy are pointing to the same object. This is an important distinction. A Java application does nothing differently when passing parameters of varying types like C++ does. Java applications pass all parameters by value, thus making copies of all parameters regardless of type.



Back to top


Examples

Using the preceding definitions and discussion, we will analyze some examples. First consider some C++ code. The C++ language uses both pass-by-value and pass-by-reference argument passing mechanisms:


Listing 1: C++ example
#include 
#include 

void modify(int a, int *P, int &r);

int main (int argc, char** argv)
{
  int val, ref;
  int *pint;

  val = 10;
  ref = 50;
  pint = (int*)malloc(sizeof(int));
  *pint = 15;

  printf("val is %d\n", val);
  printf("pint is %d\n", pint);
  printf("*pint is %d\n", *pint);
  printf("ref is %d\n\n", ref);

  printf("calling modify\n");
  //val and pint passed by value, ref is passed by reference.
  modify(val, pint, ref);
  printf("returned from modify\n\n");

  printf("val is %d\n", val);
  printf("pint is %d\n", pint);
  printf("*pint is %d\n", *pint);
  printf("ref is %d\n", ref);

  return 0;
}

void modify(int a, int *p, int &r)
{
    printf("in modify...\n");
    a = 0;
    *p = 7;
    p = 0;
    r = 0;
    printf("a is %d\n", a);
    printf("p is %d\n", p);
    printf("r is %d\n", r);
}

The output of this code is:


Listing 2: Output of C++ code
val is 10
pint is 4262128
*pint is 15
ref is 50

calling modify
in modify...
a is 0
p is 0
r is 0
returned from modify

val is 10
pint is 4262128
*pint is 7
ref is 0

This code declares three variables: two ints and one pointer. Each variable is set to an initial value and then printed. The pointer value is printed along with what it points to. All three variables are then passed as parameters to the modify function. The first two parameters are passed by value and the last parameter is passed by reference. The function prototype for the modify function shows that the last parameter is to be passed as a reference. Recall that C++ passes all parameters by value, except references, which are passed by reference.

The modify function changes the values of all three parameters:

  • The first parameter is set to 0.
  • The value the second parameter points to is set to 7, then the second parameter is set to 0.
  • The third parameter is set to 0.

The new values are printed, then the function returns. When execution returns to main, the values of the three variables, along with the value the pointer points to, are printed again. The variables passed as the first and second parameters are not affected by the modify function because they were passed by value. The value that the pointer points to did change, however. Notice that unlike the first two parameters, the variable passed as the last parameter is changed by the modify function because it is passed by reference.

Now consider similar code written in the Java language:


Listing 3: Java application
class Test
{
  public static void main(String args[])
  {
    int val;
    StringBuffer sb1, sb2;

    val = 10;
    sb1 = new StringBuffer("apples");
    sb2 = new StringBuffer("pears");
    System.out.println("val is " + val);
    System.out.println("sb1 is " + sb1);
    System.out.println("sb2 is " + sb2);
    System.out.println("");

    System.out.println("calling modify");
    //All parameters passed by value
    modify(val, sb1, sb2);
    System.out.println("returned from modify");
    System.out.println("");

    System.out.println("val is " + val);
    System.out.println("sb1 is " + sb1);
    System.out.println("sb2 is " + sb2);
  }

  public static void modify(int a, StringBuffer r1,
                            StringBuffer r2)
  {
      System.out.println("in modify...");
      a = 0;
      r1 = null;  //1
      r2.append(" taste good");
      System.out.println("a is " + a);
      System.out.println("r1 is " + r1);
      System.out.println("r2 is " + r2);
  }
}

The output of this code is:


Listing 4: Output of Java application
val is 10
sb1 is apples
sb2 is pears

calling modify
in modify...
a is 0
r1 is null
r2 is pears taste good
returned from modify

val is 10
sb1 is apples
sb2 is pears taste good

This code declares three variables: one int and two object references. Each variable is set to an initial value and printed. All three variables are then passed as parameters to the modify method.

The modify method changes the values of all three parameters.

  • The first parameter, the int, is set to 0.
  • The first object reference, r1, is set to null.
  • The second object reference, r2, retains its value but changes what it refers to by calling the append method. (This is analogous to what was done with the pointer, p, in the previous C++ example.)

When execution returns to main, the values of the three variables are printed again. The int val is unchanged as expected. The object reference sb1 is also unchanged. If sb1 was passed by reference, as many people claim, it would be null. However, since the Java programming language passes all parameters by value, a copy of the reference for sb1 is passed to the modify method. When the modify method set r1 to null at //1, it was doing so on a copy of the sb1 reference, not the original as was done in C++.

Also, note that the second object reference, sb2, prints out the new string that was set in the modify method. Even though the variable r2 in the modify method is a copy of the reference sb2, they both refer to the same object. Therefore, methods called on the copied reference change the same object.



Back to top


Writing a swap method

Given what we know about how parameters are passed, writing a swap function in C++ can be accomplished in different ways. A swap function using pointers, which are passed by value, looks like this:


Listing 5: Swap function using pointers
#include 
#include 

void swap(int *a, int *b);

int main (int argc, char** argv)
{
  int val1, val2;
  val1 = 10;
  val2 = 50;
  swap(&val1, &val2);
  return 0;
}

void swap(int *a, int *b)
{
  int temp = *b;
  *b = *a;
  *a = temp;
}

A swap function using references, which are passed by reference, looks like this:


Listing 6: Swap function using references
#include 
#include 

void swap(int &a, int &b);

int main (int argc, char** argv)
{
  int val1, val2;
  val1 = 10;
  val2 = 50;
  swap(val1, val2);
  return 0;
}

void swap(int &a, int &b)
{
  int temp = b;
  b = a;
  a = temp;
}

Both C++ code examples swap the values as expected. If Java applications used pass by reference, the following swap method would work like the C++ examples:


Listing 7: Java swap function if pass by reference worked like in C++
class Swap
{
  public static void main(String args[])
  {
    Integer a, b;

    a = new Integer(10);
    b = new Integer(50);

    System.out.println("before swap...");
    System.out.println("a is " + a);
    System.out.println("b is " + b);
    swap(a, b);
    System.out.println("after swap...");
    System.out.println("a is " + a);
    System.out.println("b is " + b);
  }

  public static void swap(Integer a, Integer b)
  {
    Integer temp = a;
    a = b;
    b = temp;
  }
}

Because the Java application passes all parameters by value, this code does not work and produces the following output:


Listing 8: Output from Listing 7
before swap...
a is 10
b is 50
after swap...
a is 10
b is 50

So how do you write a method in a Java application to swap the values of two primitive types or two object references? Because a Java application passes all parameters by value, you cannot. To swap the values, you must do so inline, outside of a method call.



Back to top


Conclusion

My intent for including this information in my book was not to split hairs or try to complicate the issue, but to alert programmers to the danger of assuming pass-by-reference semantics in Java applications. If you assume pass-by-reference semantics in a Java application, you might write a swap method like the one above, then wonder why it doesn't work.

I must admit, when I first learned that Java applications pass all parameters by value, I was suspicious. I had always assumed that because Java applications have two types, they passed the primitives by value and the references by reference, similar to C++. I had programmed in C++ for several years before moving to Java programming and anything else seemed non-intuitive. However, once I understood what was happening, I believe the Java language's method of passing everything by value is more intuitive. Ken Arnold and James Gosling, authors of The Java Programming Language, Second Edition, say it best in section 2.6.1: "There is exactly one parameter passing mode in Java -- pass by value -- and that helps keep things simple."



Resources



About the author

Peter Haggar is a Senior Software Engineer with IBM in Research Triangle Park, North Carolina. He has a broad range of programming experience, having worked on development tools, class libraries, and operating systems. At IBM, Peter works on emerging Java technology. He is currently focused on embedded Java and is also the project lead for IBM's real-time Java reference implementation. Peter is a frequent speaker on Java technology at numerous industry conferences. He has worked for IBM for more than 12 years and received a B.S. in Computer Science from Clarkson University. He can be contacted at haggar@us.ibm.com.




Rate this page


Please take a moment to complete this form to help us better serve you.



YesNoDon't know
 


 


12345
Not
useful
Extremely
useful
 


Back to top