Survey
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
* Your assessment is very important for improving the workof artificial intelligence, which forms the content of this project
School of Informatics, University of Edinburgh Computer Science 1 Ah CS1Ah Lecture Note 30 Method invocation and parameter passing In this lecture note we study how parameter values are passed to methods. At the point where a method is invoked we have the actual parameters whose values are copied and passed to the formal parameters of the method. The mechanism by which parameters are passed to methods varies from one programming language to another and it is sometimes very complex. One of the design goals for the Java programming language was that it should be (relatively) easy to learn so Java has only one type of parameter passing where other languages have three or more. Java has also chosen the simplest kind of parameter passing, termed call-by-value. Methods with and without parameters Consider the following Java program to print messages in a frilly style. It has one method which has no parameters printBanner() and one which has a single String parameter, printFrilly(). class PrintFrilly { static void printBanner() { System.out.println("<<<<<<>>>>>>"); } static void printFrilly(String s) { System.out.println("<<<" + s + ">>>"); } public static void main(String[] args) { printBanner(); for (int i = 0 ; i < args.length ; i++) { printFrilly(args[i]); } printBanner(); } } 1 // // // // // // // // // // // // // // // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 School of Informatics, University of Edinburgh Computer Science 1 Ah If we run this program with the command java PrintFrilly three little words it produces an attractive display in which the words are encased in a lovely jewelled box fashioned from the best quality angle bracket characters. <<<<<<>>>>>> <<<three>>> <<<little>>> <<<words>>> <<<<<<>>>>>> A method with no parameters, such as printBanner(), will do the same task every time that it is invoked. Such methods are sometimes useful because they attach a descriptive identifier to a block of code (the method body). Breaking a long block of statements into a number of methods with clearly defined roles is a useful programming technique which clarifies the structure of a program. The task executed by a method with parameters, such as printFrilly(), will change every time that the values of the parameters change. In the above example this method is invoked three times and performs a different task each time (a different word is printed in the frilly style in each case). 30.1 Java calls by value When a method with parameters is invoked in a Java program the actual parameter expressions are evaluated in left-to-right order to give the values which are to be passed to the method. The formal parameters are given these initial values and the method body is executed. If the formal parameter variables are updated in the method body this change is not reflected in the actual parameters which were used for this invocation. This kind of parameter passing is known as call-by-value. class CallByValue { static void assignString(String st) { st = "The string in the method"; } public static void main(String[] args) { String st = "The default initial string"; assignString(st); System.out.println(st); } } // // // // // // // // // // 1 2 3 4 5 6 7 8 9 10 When this program is executed it prints The default initial string. The key to understanding why this happens is to note that there are two variables named st which are declared in this program. One is declared at line 6 and the other as the parameter of the assignString() method at line 2. The st variable from line 6 belongs only to the main() method and the st variable declared at line 2 belongs only to the assignString() method. Neither method can alter the variable owned by the other. 2 School of Informatics, University of Edinburgh Computer Science 1 Ah As this program is executed it first initialises the String variable st in the body of the main() method. This variable’s value is retreived from memory to be passed to the assignString() method when it is invoked at line 7. This gives the initial value for the formal parameter of the method but then this initial value is overwritten by the string constant used in the assignment which is performed on line 3. The method invocation then completes and the local variable of the method is no longer accessible, nor the value which it held. When the println() method is invoked it is the default initial string which is printed. Method invocations build up a stack of activation records, one for each method invocation. These store the values of the local variables of the method, and other information such as the return address which identifies the statement in the program where execution is to begin again when this method invocation returns. Below we show how the contents of the stack of activation records changes as this program executes. st The default initial string ⇓ (the assignString() method is invoked) st The default initial string st The default initial string ⇓ (the assignment to st is performed) st The string in the method st The default initial string ⇓ (the invocation of assignString() returns) st The default initial string 30.2 Passing references by value What if we would like to structure our program in such a way that we have methods which update the state of our objects? This is possible even though the Java parameter passing mechanism is call-by-value. When we pass an object reference by value we are able to access and update any of its public fields. The following program shows how such a structure could be put into a Java program. If we wish to have a String variable updated by a method invocation we place the String variable inside a class definition as one of its public fields. In the following program we use a nested class for this purpose. The definition of the StringRef class appears in the body of the UseStringRef class. Classes can contain other classes just as they can contain fields or methods. The use of nested classes is not essential for passing updateable fields, we could instead have placed the definition of the StringRef class in a file StringRef.java and this would have had just the same effect. In this program there are two uses of StringRef variables called r. One is the local variable of the main() method, declared at line 12. The other is the formal parameter of the assignStringRef() method, introduced at line 7. Although these are different variables they both store the same reference, so they are not just equal (using equals()) they are identical (using ==). This means that when we dereference them to refer to r.st at lines 8 and 15 we access the same String variable. 3 School of Informatics, University of Edinburgh Computer Science 1 Ah class UseStringRef { static class StringRef { public String st; } static void assignStringRef(StringRef r) { r.st = "The string in the method"; } public static void main(String[] args) { StringRef r = new StringRef(); r.st = "The default initial string"; assignStringRef(r); System.out.println(r.st); } } // // // // // // // // // // // // // // // // // 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 When we execute this program it prints The string in the method. However, the mode of parameter passing is still call-by-value. The variable which was passed as a parameter was the StringRef r, whereas it was the String field r.st which was updated. Stephen Gilmore. Javier Esparza, 2003/01/03 14:09:16. 4