Let us review the computer science terms that describe how parameters can be passed to a method (or a function) in a programming language. The term call by value means that the method gets just the value that the caller provides. In contrast, call by reference means that the method gets the location of the variable that the caller provides. Thus, a method can modify the value stored in a variable that is passed by reference but not in one that is passed by value. These "call by . . . " terms are standard computer science terminology that describe the behavior of method parameters in various programming languages, not just Java. (In fact, there is also a call by name that is mainly of historical interest, being employed in the Algol programming language, one of the oldest high-level languages.) The Java programming language always uses call by value. That means that the method gets a copy of all parameter values. In particular, the method cannot modify the contents of any parameter variables that are passed to it. For example, consider the following call: double percent = 10; harry.raiseSalary(percent); No matter how the method is implemented, we know that after the method call, the value of percent is still 10. Let us look a little more closely at this situation. Suppose a method tried to triple the value of a method parameter: public static void tripleValue(double x) // doesn't work { x = 3 * x; } Let's call this method: double percent = 10; tripleValue(percent); However, this does not work. After the method call, the value of percent is still 10. Here is what happens:
There are, however, two kinds of method parameters:
You have seen that it is impossible for a method to change a primitive type parameter. The situation is different for object parameters. You can easily implement a method that triples the salary of an employee: public static void tripleSalary(Employee x) // works { x.raiseSalary(200); } When you call harry = new Employee(. . .); tripleSalary(harry); then the following happens:
As you have seen, it is easily possible and in fact very common to implement methods that change the state of an object parameter. The reason is simple. The method gets a copy of the object reference, and both the original and the copy refer to the same object. Many programming languages (in particular, C++ and Pascal) have two methods for parameter passing: call by value and call by reference. Some programmers (and unfortunately even some book authors) claim that the Java programming language uses call by reference for objects. However, that is false. Because this is such a common misunderstanding, it is worth examining a counterexample in detail. Let's try to write a method that swaps two employee objects: public static void swap(Employee x, Employee y) // doesn't work { Employee temp = x; x = y; y = temp; } If the Java programming language used call by reference for objects, this method would work: Employee a = new Employee("Alice", . . .); Employee b = new Employee("Bob", . . .); swap(a, b); // does a now refer to Bob, b to Alice? However, the method does not actually change the object references that are stored in the variables a and b. The x and y parameters of the swap method are initialized with copies of these references. The method then proceeds to swap these copies. // x refers to Alice, y to Bob Employee temp = x; x = y; y = temp; // now x refers to Bob, y to Alice But ultimately, this is a wasted effort. When the method ends, the parameter variables x and y are abandoned. The original variables a and b still refer to the same objects as they did before the method call (see Figure 4-8). Figure 4-8. Swapping object parameters has no lasting effectThis discussion demonstrates that the Java programming language does not use call by reference for objects. Instead, object references are passed by value. Here is a summary of what you can and cannot do with method parameters in the Java programming language:
The program in Example 4-4 demonstrates these facts. The program first tries to triple the value of a number parameter and does not succeed: Testing tripleValue: Before: percent=10.0 End of method: x=30.0 After: percent=10.0 It then successfully triples the salary of an employee: Testing tripleSalary: Before: salary=50000.0 End of method: salary=150000.0 After: salary=150000.0 After the method, the state of the object to which harry refers has changed. This is possible because the method modified the state through a copy of the object reference. Finally, the program demonstrates the failure of the swap method: Testing swap: Before: a=Alice Before: b=Bob End of method: x=Bob End of method: y=Alice After: a=Alice After: b=Bob As you can see, the parameter variables x and y are swapped, but the variables a and b are not affected. C++ NOTE
Example 4-4. ParamTest.java1. public class ParamTest 2. { 3. public static void main(String[] args) 4. { 5. /* 6. Test 1: Methods can't modify numeric parameters 7. */ 8. System.out.println("Testing tripleValue:"); 9. double percent = 10; 10. System.out.println("Before: percent=" + percent); 11. tripleValue(percent); 12. System.out.println("After: percent=" + percent); 13. 14. /* 15. Test 2: Methods can change the state of object 16. parameters 17. */ 18. System.out.println("\nTesting tripleSalary:"); 19. Employee harry = new Employee("Harry", 50000); 20. System.out.println("Before: salary=" + harry.getSalary()); 21. tripleSalary(harry); 22. System.out.println("After: salary=" + harry.getSalary()); 23. 24. /* 25. Test 3: Methods can't attach new objects to 26. object parameters 27. */ 28. System.out.println("\nTesting swap:"); 29. Employee a = new Employee("Alice", 70000); 30. Employee b = new Employee("Bob", 60000); 31. System.out.println("Before: a=" + a.getName()); 32. System.out.println("Before: b=" + b.getName()); 33. swap(a, b); 34. System.out.println("After: a=" + a.getName()); 35. System.out.println("After: b=" + b.getName()); 36. } 37. 38. public static void tripleValue(double x) // doesn't work 39. { 40. x = 3 * x; 41. System.out.println("End of method: x=" + x); 42. } 43. 44. public static void tripleSalary(Employee x) // works 45. { 46. x.raiseSalary(200); 47. System.out.println("End of method: salary=" 48. + x.getSalary()); 49. } 50. 51. public static void swap(Employee x, Employee y) 52. { 53. Employee temp = x; 54. x = y; 55. y = temp; 56. System.out.println("End of method: x=" + x.getName()); 57. System.out.println("End of method: y=" + y.getName()); 58. } 59. } 60. 61. class Employee // simplified Employee class 62. { 63. public Employee(String n, double s) 64. { 65. name = n; 66. salary = s; 67. } 68. 69. public String getName() 70. { 71. return name; 72. } 73. 74. public double getSalary() 75. { 76. return salary; 77. } 78. 79. public void raiseSalary(double byPercent) 80. { 81. double raise = salary * byPercent / 100; 82. salary += raise; 83. } 84. 85. private String name; 86. private double salary; 87. } |