Unit 3.6: Passing and Returning References
When you pass an object to a method in Java, you are not passing the object itself. You are passing a copy of the reference (the memory address). In Java, this is known as pass-by-value, where the "value" being passed is the reference.
Passing Object References
When an argument is an object reference, the parameter is initialized with a copy of that reference. It does not create a new independent copy of the object in memory.
Think of an object reference like a House Key:
- When you pass an object to a method, you are giving the method a copy of your key.
- Modifying the Object: If the parameter refers to a mutable object (an object that can be changed, like a
StringBuilder), the method can use its copy of the key to enter the house and rearrange the furniture (modify the object's attributes). This does affect the original object because both keys open the same house. - Reassigning the Reference: If the method throws away its key and picks up a new key to a different house (assigns a new object to the parameter), your original key and house remain unchanged.
- It is considered good programming practice to not modify mutable objects that are passed as parameters unless the program specification specifically requires it.
Task: Distinguishing between object modification and reference reassignment.
public class ReferenceTest
{
public static void modify(StringBuilder sb)
{
// This modifies the original object because it uses the shared reference
sb.append("World");
}
public static void reassign(StringBuilder sb)
{
// This only changes the local copy of the key (the parameter)
// It does NOT affect the caller's variable
sb = new StringBuilder("New Object");
}
public static void main(String[] args)
{
StringBuilder myText = new StringBuilder("Hello");
modify(myText);
System.out.println(myText); // Prints "HelloWorld" (The object was changed)
reassign(myText);
System.out.println(myText); // Still prints "HelloWorld" (The original reference is unchanged)
}
}
Returning Objects
When the return expression in a method evaluates to an object reference, the reference is returned, not a reference to a new copy of the object.
- This means the code that called the method receives a "key" to the exact same object that was inside the method.
- No new object is created during the return process; the caller simply gets a way to access an existing object.
Task: Returning a reference to the current object.
public class Wallet
{
private int money = 100;
// This method returns a reference to THIS specific object
public Wallet getMyWallet()
{
return this;
}
}
// In main method:
Wallet myWallet = new Wallet();
Wallet sharedWallet = myWallet.getMyWallet(); // sharedWallet is an ALIAS for myWallet
// Both variables point to the exact same object in memory.
Accessing Private Members
A fundamental rule of encapsulation is that methods cannot access the private data or methods of a parameter that holds a reference to an object.
The Exception: You can access those private members if the parameter is the same type as the method’s enclosing class.
- In other words, an object can see the private "secrets" of another object, as long as they are both instances of the same class.
Task: Accessing private members of a parameter of the same class type.
public class Student
{
private int id;
public Student(int id)
{
this.id = id;
}
public boolean hasSameID(Student other)
{
// This is VALID because we are inside the Student class code.
// We can access other.id directly even though it is private.
return this.id == other.id;
}
}
If you tried to access student.id from a different class (like Teacher), it would cause a compile-time error because the code is outside the enclosing class.
Task: Identifying a compile-time error when accessing private members from another class.
// INSIDE A DIFFERENT CLASS
public class Teacher
{
public void printID(Student s)
{
// ERROR: id has private access in Student
System.out.println(s.id);
}
}