Parameter Passing in Java

This is something I wrote about how Java handles passing parameters for an introductory programming class. Since I already knew the basics, I took the opportunity to take a deep dive into the pass-by-reference and pass-by-value methods of param passing. I hope others will find this as edifying as I did.

Parameters are a part of the interface of a subroutine that enable data to be passed into the subroutine when it is called (Eck, 2016). This enables the subroutine to dynamically incorporate the appropriate data into its operation. Take the following program for example:

public class AddNumbers {
public static void main(String[] args) {
int result = addNumbers();
System.out.println("2 + 2 = " + result);
}
public static int addNumbers() {
return 2 + 2;
}
}

When this code is run, the program adds the numbers 2 and 2 together. This is great, it makes the addNumbers subroutine useless for adding numbers other than 2 and 2. In order to generalize the use case, we need to add parameters. This is what the program might look like now:

public class AddNumbers {
public static void main(String[] args) {
int num1, num2, result;
// Let the user input the numbers they want to add
System.out.println("Enter the first integer:");
num1 = TextIO.getlnInt();
System.out.println("Enter the second integer:");
num2 = TextIO.getlnInt();
// Add the two numbers
result = addNumbers(num1, num2);
// Print the result
System.out.println(num1 + " + " num2 + " = " + result);
}
public static int addNumbers(int a, int b) { // The variable names a and b are arbitrary
return a + b;
}
}

In this example, the addNumbers subroutine can be used to add any two integers, and we don't have to even decide which integers they are until runtime. Using parameters in this way allows us to create an interactive program that accepts user inputs and uses it to generate the appropriate output. (Notice also the line public static void main(String[] args), indicating the main method takes an array of String objects as its argument. This enables the user to pass in data or configurations from the command line when running the program. In this sense, the program itself can be seen as a subroutine of the computer as a whole, which operates on data that the user passes in (Eck, 2016).)

A subroutine definition includes (among other things) the name of the subroutine and its formal parameters. In the case of addNumbers, the formal parameters are a and b. Formal parameters, like variables, have a type. This is the type of data that the subroutine is able to process. When the subroutine is called, actual parameters must be passed in. These actual parameters must be of the type dictated by the formal parameters (Reid, n.d.). If you pass in non-int values to addNumbers, an exception will be raised indicating that the wrong type was passed in.

The key distinction between formal parameters and actual parameters is that formal parameters are names, whereas actual parameters are the data values that are assigned to those names (CforLearn.com, 2015). So the formal parameters of addNumbers are a and b. The actual parameters don't exist until the subroutine is invoked. If I invoke the subroutine, as in addNumbers(1,2);, the actual parameters, or arguments, are 1 and 2, respectively.

Unlike regular variables, values are not assigned to formal parameters with an assignment statement. Instead, when the subroutine is called, its formal parameters are assigned to the actual parameters (i.e., the values actually passed into the subroutine). For example, in the code addNumbers(2, 4);, the formal parameters num1 and num2 are assigned to the actual parameters, which are the values 2 and 4. Whenever a subroutine is called, it must be passed actual parameters; otherwise, an exception will be thrown (Eck, 2016).

Within the body of a subroutine, formal parameter names are used just like other variables (Eck, 2016). As you can see, within the body of addNumbers, the formal parameter names a and b are used in the expression return a + b;. This expression adds the two integers that have been passed in and returns the result. Once the addNumbers method exits, the parameter names a and b are no longer defined.

When a subroutine is defined with formal parameters, space for those parameters is allocated in memory in the same way as occurs when a variable is declared. What happens when the subroutine is called varies by language. The two basic approaches are pass by value and pass by reference (Miller, 2016). Java uses the pass by value method to associate actual parameters with the formal parameter names (Reid, n.d.), but I’ll explain both methods here as I enjoyed learning about them and hope others will as well.

Pass by Value

In the pass-by-value method, the value of the actual parameter is copied into the location in memory allocated for the formal parameter. The implications of this are important because it means the actual value of an object passed into a subroutine is not changed within the subroutine; instead, a copy of the value is modified (Kumar, 2016).

The pass-by-value method is best illustrated using a swap method. In the following example, we have a class called MyObject. Every instance of MyObject is instantiated with a name that is assigned to an instance variable. The MyObject class looks like this:

public class MyObject {
private String name;
public MyObject(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
}

Our main program instantiates two MyObject objects called foo and bar, respectively. Next, it implements a swap method that attempts to swap foo and bar such that the MyObject called foo is replaced with the MyObject called bar, and vice versa.

public class PassByValue {
public static void main(String[] args) {
// Instantiate two objects of the MyObject class named "foo" and "bar"
MyObject foo = new MyObject( "foo" );
MyObject bar = new MyObject( "bar" );
// Print the names of objects foo and bar to verify their names
// have been set
System.out.println("First object's name is " + foo.getName());
System.out.println("Second object's name is " + bar.getName());
// Attempt to swap the values of foo and bar
swap( foo, bar );
// Check to see if the objects have been swapped
System.out.println("First object's name is now " + foo.getName());
System.out.println("Second object's name is now " + bar.getName());
}
private static void swap(MyObject obj1, MyObject obj2) {
MyObject temp = obj1;
obj1 = obj2;
obj2 = temp;
}
}

Now, you might expect the output of this program to look like this:

First object's name is foo
Second object's name is bar
First object's name is now bar
Second object's name is now foo

However, since Java uses the pass-by-value method, the output is actually this:

First object's name is foo
Second object's name is bar
First object's name is now foo
Second object's name is now bar

How come the objects haven’t been swapped as expected? The answer is that, since Java copies the foo and bar objects before passing them to the swap subroutine, only the copies actually get swapped! The original objects are unchanged (Kumar, 2016).

Pass by Reference

Since Java always uses the pass-by-value method to assign actual parameters to formal parameters, it isn’t possible to give a detailed example of the pass-by-reference method in Java. Consequently, I’ll explain the concept referring to the example above.

In the pass-by-reference method, instead of copying the value of the actual parameter into the formal parameter, the formal parameter is assigned to a reference, or pointer, to the exact object being passed into the subroutine (Stanchfield, 2014). In the example above, this would mean that the foo and bar objects are not copied. Instead, the formal parameters point to the actual foo and bar objects themselves. As a result, when the swap method was called, the foo object itself would be replaced with the bar object, and vice versa. In this case, the output would look like this:

First object's name is foo
Second object's name is bar
First object's name is now bar
Second object's name is now foo

To summarize, formal parameters in Java are the names that are declared as parameters at the point where a subroutine is defined. Since Java uses the pass-by-value method to assign actual parameters to formal parameters, the actual parameters to a method are copies of the objects specified in the method call. Going back to our first example, when the addNumbers method is called in the code return addNumbers(num1, num2);, the user-supplied values num1 and num2 are copied and the copies passed to addNumbers (instead of num1 and num2 being passed into the addNumbers subroutine directly. This behavior sets Java apart from languages that use the pass-by-reference method, such as Perl, that use the call-by-reference method (Marshall, 2005), or Python, which uses both methods depending on the circumstances (Knupp, 2012).

CforLearn.com. (2015). C formal vs. actual parameters. Retrieved from http://www.c4learn.com/c-programming/c-formal-vs-actual-function-parameter/.

Eck, D. J. (2016). Introduction to programming using Java (7th ed). Retrieved from http://math.hws.edu/javanotes/index.html.

Knupp, J. (2012). Is Python call-by-value or call-by-reference? Neither. Retrieved from https://jeffknupp.com/blog/2012/11/13/is-python-callbyvalue-or-callbyreference-neither/.

Kumar, P. (2016). Java is pass by value and not pass by reference. Retrieved from http://www.journaldev.com/3884/java-is-pass-by-value-and-not-pass-by-reference.

Marshall, D. (2005). Practical Perl programming. Retrieved from https://users.cs.cf.ac.uk/Dave.Marshall/PERL/perl_caller.html.

Miller, J. R. (2016). Moving from Java to C++. Retrieved from https://people.eecs.ku.edu/~miller/Courses/JavaToC++/ParameterPassing.html.

Reid, K. (n.d.). Java method arguments. Retrieved from http://www.cs.toronto.edu/~reid/web/javaparams.html.

Stanchfield, S. (2014). Java is pass-by-value, dammit! Retrieved from http://javadude.com/articles/passbyvalue.htm.

Senior Engineer at Envato