Unit 3 · 20 min

3.6 Methods: Passing and Returning References of an Object

One object, two arrows: whatever you do to the object through one arrow, the other arrow sees.

Summary, objectives and course and exam description (CED) codes

Java always passes arguments by value; when the argument is an object reference, the value copied is the reference, so the parameter and the argument refer to the same object. A method can use that reference to change a mutable object, and returning an object returns the reference, not a new copy. A method can use the private data of a parameter only when the parameter's type is the method's own class.

By the end of this session you can

  • 3.6.A Develop code to define behaviors of an object through methods written in a class using object references, and determine the result of calling these methods.

3.6.A3.6.A.13.6.A.23.6.A.3

Reviewed against the CED on

Know this already? Jump to the checkpoint.

1LearnThe notes, the traps and how to remember them

1. Passing an object: the reference is copied

Java passes arguments by value (the AP® term is call by value): the parameter is initialized with a copy of the value stored in the argument. For an object, the variable stores a reference, so the parameter gets a copy of that reference. It does not create a new, independent copy of the object 3.6.A.1. The parameter and the argument now refer to the same object. Two references to one object are called aliases.

If the object is mutable, the method can use its reference to change the object’s state 3.6.A.1.

This class is used on the whole page:

public class BankAccount
{
    private String owner;
    private int balance;

    public BankAccount(String name, int start)
    {
        owner = name;
        balance = start;
    }

    public String getOwner()
    {
        return owner;
    }

    public int getBalance()
    {
        return balance;
    }

    public void deposit(int amount)
    {
        balance += amount;
    }

    /** Returns true if this account has a larger balance than other */
    public boolean hasMoreThan(BankAccount other)
    {
        return balance > other.balance;
    }

    /** Moves amount from this account to other */
    public void transferTo(BankAccount other, int amount)
    {
        balance -= amount;
        other.balance += amount;
    }

    public String toString()
    {
        return owner + ": " + balance;
    }
}

A method in another class receives an account and adds 10 percent interest:

public class Bank
{
    public static void addInterest(BankAccount acct)
    {
        acct.deposit(acct.getBalance() / 10);
    }
}
BankAccount mine = new BankAccount("Rosa", 200);
Bank.addInterest(mine);
System.out.println(mine);

Output:

Rosa: 220

During the call, memory looks like this:

mine (caller)    [ ref ] ---+
                            +---> BankAccount object: owner "Rosa", balance 200 -> 220
acct (parameter) [ ref ] ---+

Only one BankAccount object exists (println shows it through its toString method; writing toString is background, not tested on the AP® exam). acct.deposit(...) changed it, and mine sees the change.

2. Reassigning the parameter does not change the caller

Because the reference was copied, giving the parameter a new object only changes the method’s copy. The caller’s variable still refers to the original object.

public class Bank
{
    public static void replace(BankAccount acct)
    {
        acct = new BankAccount("Temp", 0);
        acct.deposit(5);
    }
}
BankAccount mine = new BankAccount("Rosa", 200);
Bank.replace(mine);
System.out.println(mine);

Output:

Rosa: 200
mine (caller)    [ ref ] ---> BankAccount: owner "Rosa", balance 200   (untouched)
acct (parameter) [ ref ] ---> BankAccount: owner "Temp", balance 5     (gone after the call)
Inside the method Does the caller see a change?
acct.deposit(5); (call a mutator through the parameter) Yes: same object
acct = new BankAccount("Temp", 0); (reassign the parameter) No: only the copy of the reference moved

Watch out: a String parameter is a reference too, but String objects are immutable. No method can change the caller’s string; methods like substring return a new string instead.

3. Do not change parameters unless the specification says so

It is good programming practice not to modify mutable objects that are passed as parameters, unless the specification requires it 3.6.A.1. The caller does not expect a method that only “calculates” something to change their object.

This method counts how many monthly deposits it takes to reach a goal. The first version is wrong: it deposits into the caller’s real account while it counts.

public class Planner
{
    // BAD: changes the account it was given
    public static int monthsToGoal(BankAccount acct, int goal, int monthly)
    {
        int months = 0;
        while (acct.getBalance() < goal)
        {
            acct.deposit(monthly);
            months++;
        }
        return months;
    }
}
BankAccount savings = new BankAccount("Rosa", 100);
System.out.println(Planner.monthsToGoal(savings, 250, 50));
System.out.println(savings);

Output:

3
Rosa: 250

The good version copies the balance into a local int and leaves the object alone:

public class Planner
{
    // GOOD: reads the account but does not change it
    public static int monthsToGoal(BankAccount acct, int goal, int monthly)
    {
        int balance = acct.getBalance();
        int months = 0;
        while (balance < goal)
        {
            balance += monthly;
            months++;
        }
        return months;
    }
}
BankAccount savings = new BankAccount("Rosa", 100);
System.out.println(Planner.monthsToGoal(savings, 250, 50));
System.out.println(savings);

Output:

3
Rosa: 100

4. Returning a reference

When the return expression evaluates to an object reference, the reference is returned, not a reference to a new copy of the object 3.6.A.2. The caller then holds an alias to the object stored inside the class.

public class Club
{
    private String name;
    private BankAccount treasury;

    public Club(String clubName, int startMoney)
    {
        name = clubName;
        treasury = new BankAccount(clubName, startMoney);
    }

    /** Returns the club's own account (an alias) */
    public BankAccount getTreasury()
    {
        return treasury;
    }

    /** Returns a new account with the same values (a copy) */
    public BankAccount getTreasuryCopy()
    {
        return new BankAccount(treasury.getOwner(), treasury.getBalance());
    }

    public int funds()
    {
        return treasury.getBalance();
    }
}
Club chess = new Club("Chess", 500);
BankAccount a = chess.getTreasury();
a.deposit(100);
System.out.println(chess.funds());
BankAccount b = chess.getTreasuryCopy();
b.deposit(1000);
System.out.println(chess.funds());

Output:

600
600

a refers to the club’s real account, so the deposit through a changed the club. b refers to a new object, so the deposit through b did not.

5. Private access through a parameter of the same class

Methods cannot access the private data and private methods of a parameter that refers to an object, unless the parameter is the same type as the method’s enclosing class 3.6.A.3.

That is why hasMoreThan and transferTo in BankAccount can use other.balance directly: other is a BankAccount, and the code is inside BankAccount.

BankAccount x = new BankAccount("Rosa", 300);
BankAccount y = new BankAccount("Theo", 120);
x.transferTo(y, 50);
System.out.println(x + ", " + y);
System.out.println(x.hasMoreThan(y));

Output:

Rosa: 250, Theo: 170
true

The same expression in a different class does not compile:

public class Auditor
{
    public static boolean isNegative(BankAccount acct)
    {
        return acct.balance < 0;
    }
}

Compiler says:

error: balance has private access in BankAccount

The fix is to use the public accessor: return acct.getBalance() < 0;.

Watch out: transferTo changes its parameter other on purpose. That is fine because moving money into the other account is exactly what the method’s specification says it does 3.6.A.1.

Lock it in: memory hooks

  • Pass by valueJava always copies the value in the variable. For objects, that value is an arrow (a reference), so you get a second arrow to the same object.
  • Change vs reassignparam.mutator() changes the shared object. param = new Thing() only moves the method's own arrow.
  • Private accessSame class, same keys: a BankAccount method can open another BankAccount's private data.

Common misconceptions

  • "Java passes objects by reference, so a method can make the caller's variable point to a different object."

    Not quite. Java passes by value. For an object the value is a copy of the reference. The method can change the object through it, but assigning a new object to the parameter changes only the parameter, never the caller's variable.

  • "Passing an object to a method gives the method its own copy of the object."

    Not quite. No new object is created. The parameter and the argument are aliases: two references to one object.

  • "An accessor that returns an object returns a safe copy."

    Not quite. Returning an object reference returns the reference itself. The caller can use it to change the object inside your class, unless you return a new copy on purpose.

Exam traps

  • A void method that calls a mutator on its object parameter does change the caller's object.
  • A method that sets its parameter to a new object does not change the caller's object.
  • Strings are immutable: a method can never change the caller's String, even though it receives a reference to it.
  • other.balance compiles inside the BankAccount class but not inside any other class.

2PracticeRecall it, then check yourself

In 30 seconds

  1. An object reference argument: the parameter gets a copy of the reference, not a copy of the object.
  2. Parameter and argument are aliases, so a mutator called through the parameter changes the caller's object.
  3. Assigning a new object to the parameter does not change the caller's variable.
  4. Do not modify mutable objects passed as parameters unless the specification requires it.
  5. Returning an object returns the reference, not a new copy of the object.
  6. A method can reach a parameter's private data only if the parameter is the same type as the method's class.

Cover this list, say the points out loud, then take the checkpoint without scrolling back up.

Checkpoint · 5 questions

Checkpoint: Methods: Passing and Returning References of an Object

Pick an answer to mark it. Every answer is explained, and you can try any question again. Your saved score counts first tries only, and stays in this browser.

  1. 1 Consider the following classes. The code segment below the classes appears in a method in another class. What is printed as a result of executing the code segment? 3.6.A.1
    public class Box
    {
        private int size;
    
        public Box(int s)
        {
            size = s;
        }
    
        public int getSize()
        {
            return size;
        }
    
        public void grow()
        {
            size++;
        }
    }
    
    public class Mover
    {
        public static void change(Box b)
        {
            b.grow();
            b = new Box(10);
            b.grow();
        }
    }
    
    Box box = new Box(3);
    Mover.change(box);
    System.out.println(box.getSize());
    Show answer

    Answer: B. b starts as a copy of the reference in box, so the first b.grow() changes the caller's object from 3 to 4. Then b = new Box(10) makes only the parameter refer to a new object, and the second grow changes that new object to 11, which the caller never sees. The option 3 assumes objects are copied when passed, and 11 assumes the reassignment changes the caller's variable.

  2. 2 Consider the following Team class, which uses the Box class from the previous question. The code segment below the class appears in a method in another class. What is printed as a result of executing the code segment? 3.6.A.2
    public class Team
    {
        private Box gear;
    
        public Team()
        {
            gear = new Box(5);
        }
    
        public Box getGear()
        {
            return gear;
        }
    
        public int gearSize()
        {
            return gear.getSize();
        }
    }
    
    Team t = new Team();
    Box g = t.getGear();
    g.grow();
    g.grow();
    System.out.println(t.gearSize() + " " + g.getSize());
    Show answer

    Answer: D. getGear returns the reference stored in gear, not a reference to a new copy, so g and gear refer to the same Box. Growing it twice through g changes the team's box from 5 to 7, and both expressions report 7. The option 5 7 assumes the accessor returned a copy of the object.

  3. 3 The Box class from question 1 has a private instance variable size and a public accessor getSize. Which of the following methods compiles without error when it replaces /* missing code */ in the Shelf class below? 3.6.A.3
    public class Shelf
    {
        /* missing code */
    }
    Show answer

    Answer: A. Shelf is a different class from Box, so it cannot access the private variable size of its Box parameters and must use the public accessor getSize. Using size without an object does not compile in Shelf either, since Shelf has no such variable. Box has no method named size.

  4. 4 The following method is added inside the Box class from question 1. Which of the following best describes the result? 3.6.A.3
    public boolean biggerThan(Box other)
    {
        return size > other.size;
    }
    Show answer

    Answer: C. A method may use the private data of a parameter when the parameter is the same type as the method's enclosing class. Here the method is in Box and other is a Box, so other.size is allowed. size alone means the size of the object whose method is called, and other.size is the other box's size, so two different objects are compared. A static method could not use size without an object at all.

  5. 5 The following method is specified to return a short description of a Box from question 1. Which of the following best describes a problem with the method? 3.6.A.1
    /** Returns a description of b */
    public static String describe(Box b)
    {
        b.grow();
        return "Box of size " + b.getSize();
    }
    Show answer

    Answer: C. b refers to the caller's object, so b.grow() changes the caller's box. Good practice is not to modify a mutable object passed as a parameter unless the specification requires it, and this one only asks for a description. Static methods can have object parameters, no copy of the box is made, and the method returns a String.

3PrevailLock it in for exam day

By the numbers

Name each list from memory, then reveal it to check. Each list shows how many items to recall.

Key terms: flip the cards

Read the term, say the definition out loud, then flip to check. Struggling a little to remember is what makes it stick.

  • Passing referencestap to flip

    When an argument is an object reference, the parameter gets a copy of the reference, so both refer to the same object.

    Example and CED codes
  • Aliasingtap to flip

    Two or more references that refer to the same object, so a change made through one reference is seen through the others.

    Example and CED codes
  • Call by valuetap to flip

    The way Java passes arguments: each parameter is initialized with a copy of the argument.

    Example and CED codes
  • Object referencetap to flip

    The value a reference variable holds: it can be thought of as the memory address of the object.

    Example and CED codes
  • Parametertap to flip

    A variable declared in the header of a method or constructor. It receives the value passed in and can be used in the body.

    Example and CED codes
  • Argumenttap to flip

    A value passed into a method or constructor when it is called.

    Example and CED codes
  • Objecttap to flip

    A specific instance of a class with defined attributes.

    Example and CED codes
  • nulltap to flip

    A special literal meaning a reference variable is not associated with any object.

    Example and CED codes
  • Encapsulationtap to flip

    Keeping the implementation details of a class hidden from other classes, mainly by making instance variables private.

    Example and CED codes

Questions students ask

Is Java pass by value or pass by reference?

Java is always pass by value. When the argument is an object, the value that is copied is the reference, so the method can change the object but cannot make the caller's variable refer to a different object.

Why did my object change after I passed it to a method?

The parameter received a copy of the reference, so it refers to the same object as your variable. If the method called a mutator through the parameter, the one shared object changed.

Can a method access the private variables of another object?

Only if that object's type is the same class the method is written in. A BankAccount method can read other.balance when other is a BankAccount; a method in a different class cannot.

What is aliasing in Java?

Aliasing happens when two references refer to the same object. Changes made through one reference are visible through the other.

Was this page helpful?

No names are ever shown, and every public comment is checked by us first. Please do not include personal details. To get a reply, email [email protected].

↑ Top

Enlarged view of the selected figure