7.3 Determine the effect upon object references and primitive values when they are passed into methods that perform assignments or other modifying operations on the parameters.
Methods can be declared to take primitives and/or object references. You need to know how (or if) the caller's variable can be affected by the called method. The difference between object reference and primitive variables, when passed into methods, is huge and important. To understand this section, you'll need to be comfortable with the assignments section covered in the first part of this chapter.
When you pass an object variable into a method, you must keep in mind that you're passing the object reference, and not the actual object itself. Remember that a reference variable holds bits that represent (to the underlying VM) a way to get to a specific object in memory (on the heap). More importantly, you must remember that you aren't: even passing the actual reference variable, but rather a copy of the reference variable. A copy of a variable means you get a copy of the bits in that variable, so when you pass a reference variable, you're passing a copy of the bits representing how to get to a specific object. In other words, both the caller and the called method will now have identical copies of the reference, and thus both will refer to the same exact ( not a copy) object on the heap.
For this example, we'll use the Dimension class from the java.awt package:
1. import java.awt.Dimension; 2. class ReferenceTest { 3. public static void main (String [] args) { 4. Dimension d = new Dimension(5,10); 5. ReferenceTest rt = new ReferenceTest(); 6. System.out.println("Before modify() d.height = " + d.height); 7. rt.modify(d); 8. System.out.println("After modify() d.height = " + d.height); 9. } 10. void modify(Dimension dim) { 11. dim.height = dim.height + 1; 12. System.out.println("dim = " + dim.height); 13. } 14. }
When we run this class, we can see that the modify() method was indeed able to modify the original (and only) Dimension object created on line 4.
C:\Java Projects\Reference>java ReferenceTest Before modify() d.height = 10 dim = 11 After modify() d.height = 11
Notice when the Dimension object on line 4 is passed to the
modify()
method, any changes to the object that occur inside the method are being made to the object whose reference was passed. In the
If Java
It makes no difference if you're passing primitive or reference variables, you are always passing a copy of the bits in the variable. So for a primitive variable, you're passing a copy of the bits representing the value. For example, if you pass an int variable with the value of 3 , you're passing a copy of the bits representing 3 . The called method then gets its own copy of the value, to do with it what it likes.
And if you're passing an object reference variable, you're passing a copy of the bits representing the reference to an object. The called method then gets its own copy of the reference variable, to do with it what it likes. But because two identical reference variables refer to the exact same object, if the called method modifies the object (by invoking setter methods, for example), the caller will see that the object the caller's original variable refers to has also been changed. In the
The bottom line on pass-by-value: the called method can't change the caller's variable, although for object reference variables, the called method can change the object the variable referred to. What's the difference between changing the variable and changing the object? For object references, it means the called method can't
void bar() { Foo f = new Foo(); doStuff(f) ; } void doStuff(Foo g) { g.setName("Boo"); g = new Foo(); }
Let's look at what happens when a primitive variable is passed to a method:
class ReferenceTest { public static void main (String [] args) { int a = 1; ReferenceTest rt = new ReferenceTest(); System.out.println("Before modify() a = " + a); rt.modify(a); System.out.println("After modify() a = " + a) ; } void modify(int number) { number = number + 1; System.out.println("number = " + number); } }
In this simple program, the variable
a
is passed to a method called
modify()
, which
Before modify() a = 1 number = 2 After modify() a = 1
Notice that a did not change after it was passed to the method. Remember, it was a copy of a that was passed to the method. When a primitive variable is passed to a method, it is passed by value, which means pass-by-copy-of-the-bits-in-the-variable.
|
|
The Shadowy World of Variables
Just when you think you've got it all figured out, you see a piece of code with variables not behaving the way you think they should. You might have
The effect of shadowing is to hide the previously declared variable in such a way that it may look as though you're using the hidden variable, but you're actually using the shadowing variable. You might find reasons to shadow a variable intentionally, but typically it happens by
You can shadow an instance variable by declaring a local variable of the same
class Foo { static int
size
*
7; static void changeIt(int size) { size = size + 200; Systsm.out.println("size in changelt is " + size); } public static void main (String [] args) { Foo f = new Foo() ; System.out.println("size = " + size); changeIt(size); System.out.println("size after changeIt is " + size); } }
The preceding code appears to change the size instance variable in the changeIt() method, but because changeIt() has a parameter named size , the local size variable is modified while the instance variable size is untouched. Running class Foo prints
%java Foo size = 7 size in changeIt is 207 size after changelt is 7
Things become more interesting when the shadowed variable is an object reference, rather than a primitive:
class Bar { int barNum = 28; } class Foo { Bar myBar =new Bar(); void changelt(Bar myBar) { myBar.barNum = 99; System.out.println("myBar.barNum in changeIt is " + myBar.barNum); myBar = new Bar() ; myBar.barNum = 420; System.out
.
println("myBar.barNum in changelt is now " + myBar.barNum); } public. static void main (String [] args) { Foo f = new Foo() ; System. out .println.("f.myBar.barNum is " + f.myBar.barNum); f.changeIt {f.myBar); System.out.println("f .myBar.barNum after changeIt is " + f.myBar.barNum) ; } }
The preceding code prints out this:
f.myBar.barNum is 28 myBar.barNum in changelt is 99 myBar.barNum in changeIt is now 420 f, myBar. barNum after changeIt is 99
You can see that the shadowing variable (the local parameter myBar in changeIt() .) can still affect the myBar instance variable, because the myBar parameter receives a reference to the same Bar object. But when the local myBar is reassigned a new Bar object, which we then modify by changing its barNum value, Foo's original myBar instance variable is untouched.
|
|

SCJP Sun Certified Programmer for Java 6 Exam 310-065

OCP Java SE 6 Programmer Practice Exams (Exam 310-065) (Certification Press)

Head First Servlets and JSP: Passing the Sun Certified Web Component Developer Exam

SCJP Exam for J2SE 5: A Concise and Comprehensive Study Guide for The Sun Certified Java Programmer Exam