Monday, 13 July 2015

Passing Arguments To Methods In Java


Variables are always passed by copy in Java. This is an unchanging rule of the language, but one that can be easily misinterpreted when running code.

Take the following example, which you should place in a package called "misc":


package misc;
public class ArgumentsAreCopies {
static int number = 1;
public static void main(String[] arguments){
ArgumentsAreCopies copies = new ArgumentsAreCopies();
System.out.println("Number before/outside method: " + number);
copies.increaseNumber(number);
System.out.println("Number after/outside method: " + number);
}
static void increaseNumber(int num){
num++;
System.out.println("Number in method: " + num);
}
}
When run, this program should output the following:

Number before/outside method: 1
Number in method: 2
Number after/outside method: 1

This makes sense because, as previously mentioned, arguments are passed as copies. We aren't changing the original number variable.

However, what happens when we put something that isn't a primitive type in there, like an object?

Use the following code to create a new class, in the same package:

package misc;
public class TestObject {
int attributeOne;  int attributeTwo ; 
public void setAttributeOne(int attributeOne) { this.attributeOne = attributeOne; }
public void setAttributeTwo(int attributeTwo) { this.attributeTwo = attributeTwo; }
public String toString(){ return "Attribute one: " + attributeOne + " Attribute two: " + attributeTwo; }}

For the sake of brevity, this class ignores best practice (getter methods, etc). Change the "ArgumentsAreCopies" class to the following and run it:

package misc;
public class ArgumentsAreCopies {
static TestObject test = new TestObject();  public static void main(String[] arguments){ ArgumentsAreCopies copies = new ArgumentsAreCopies(); System.out.println("Test Object outside method: " + test.toString()); copies.increaseNumber(test); System.out.println("Test Object outside method: " + test.toString()); } public void increaseNumber(TestObject test){ test.setAttributeOne(3); System.out.println("Test Object inside method: " + test.toString()); }}
After running this, you should get the following output:

Test Object outside method: Attribute one: 0 Attribute two: 0
Test Object inside method: Attribute one: 3 Attribute two: 0
Test Object outside method: Attribute one: 3 Attribute two: 0

Looks strange because the field changed this time, right? This isn't a bug or anything of the sort at all. What's happening here is that a copy of the TestObject is being sent to the method, but  that copy still points to the same fields.

We aren't changing the object in this case (We can't anyway), but the fields that both the TestObject copy and the original TestObject both point towards the same fields/values. And those values are not being passed into the method, therefore are not copies.

This is an easy concept to get tripped up on and might not make sense when you first encounter it, but as you continue down the path of Java you will find that it is consistent with these kind of "rules".


No comments:

Post a Comment