Skip to content
HopperHopper

Course navigation

Unit 3 · Class CreationTopic 3.6

Methods: Passing and Returning References of an Object

  • About 55 minutes
  • 5 sections
  • Runnable Java examples
  • Practice questions

Before you start

About 55 minutes

Section 1 of 5

3.6.1 Passing an Object Reference

A game app keeps a Player object for each player, with a name and a point total. A Scorekeeper object awards bonuses. Its method needs to receive a whole player, not just a number, and the bonus has to stick: after the method finishes, the player in main should have the extra points. In Topic 3.5 every parameter you wrote was a primitive, such as an int, and changing an int parameter never changed anything outside the method. So what happens when the argument is an object?

Start from two things you already know. First, from Topic 3.5: a parameter is initialized with a copy of its argument. Second, from Topic 1.13: a variable such as Player star does not hold the player object itself. It holds a reference, the address of where the object lives in memory.

Put those together and the answer follows. When the argument is a reference variable, what gets copied into the parameter is the reference, the address. The object is not copied. There is still exactly one Player object, and now two variables lead to it: the caller’s variable and the method’s parameter. In the words of Topic 2.6, the parameter becomes an alias of the caller’s object for as long as the method runs.

Think of handing a friend a slip of paper with your home address copied onto it. Your friend has their own slip, but there is still only one house. If they go there and paint the front door, you will see the new color when you come home. (The analogy stops at the slip itself: if your friend scribbles a different address on their slip, your slip is unchanged. That case is the subject of 3.6.2.)

Because the method can reach the real object, it can call that object’s mutators and change its state. An object whose state can be changed after it is created, such as a Player with an addPoints mutator, is called a mutable object. A String is not mutable, as you saw in Topic 1.15.

Key idea

When the argument is an object, the parameter gets a copy of the reference, not a copy of the object. The parameter and the caller’s variable refer to the same object, so a method can use the parameter to change a mutable object’s state.

Most programs in this chapter use a Player class like the one in the next example: private name and points, a constructor, two accessors, and the mutator addPoints. In your own projects each class is public and goes in its own file. To keep each example runnable as a single file, the extra classes here leave off public, because Java allows only one public class per file. Once you have read Player here, you can skip it at the bottom of later examples.

Worked example: A bonus that sticks

Watch which object line 16 changes, and what line 8 prints afterward.

BonusByReference.java
public class BonusByReference
{
    public static void main(String[] args)
    {
        Player star = new Player("Ada", 10);
        Scorekeeper keeper = new Scorekeeper();
        keeper.awardBonus(star);
        System.out.println("Back in main: " + star.getPoints());
    }
}

class Scorekeeper
{
    public void awardBonus(Player p)
    {
        p.addPoints(5);
        System.out.println("Inside awardBonus: " + p.getPoints());
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}

Line 5 builds one Player object. Call its address “address A.” star holds that address.

Line 7 calls awardBonus(star). The parameter p is initialized with a copy of what star holds, which is “address A.” No new appears anywhere in the call, so no second player is built. While the method runs, memory looks like this:

Variable Holds Object at that address
star (in main) reference to address A Player “Ada”, 10 points
p (in awardBonus) reference to address A (the same object)

Line 16 follows p to address A and calls addPoints(5), so that one object now has 15 points. Line 17 prints Inside awardBonus: 15.

The method ends and p disappears, but the object at address A is still there with its 15 points. Back in main, line 8 follows star to that same object:

Variable Holds Object at that address
star (in main) reference to address A Player “Ada”, 15 points
Inside awardBonus: 15
Back in main: 15

Now change one thing: pass a primitive instead of an object. This version gives awardBonus an int parameter and adds 5 to it.

BonusByValue.java
public class BonusByValue
{
    public static void main(String[] args)
    {
        int adaScore = 10;
        Scorekeeper keeper = new Scorekeeper();
        keeper.awardBonus(adaScore);
        System.out.println("Back in main: " + adaScore);
    }
}

class Scorekeeper
{
    public void awardBonus(int score)
    {
        score = score + 5;
        System.out.println("Inside awardBonus: " + score);
    }
}
Inside awardBonus: 15
Back in main: 10

Line 7 copies the value 10 into score. Line 16 changes score to 15, but score is a separate box from adaScore, and there is no object behind either one. adaScore is still 10. Side by side:

Argument type What the parameter gets Can the method change what the caller sees?
Primitive (int) A copy of the value No. The caller’s variable is separate.
Object (Player) A copy of the reference (address) Yes, by calling a mutator on the shared object.

In both cases Java copies what the argument variable holds. The difference is what it holds: a number in one case, an address in the other.

Watch out

Thinking the method gets its own copy of the object. Many students picture awardBonus(star) as handing the method a photocopy of the player, so they predict Back in main: 10 for BonusByReference. That would be true only if the call made a new object, and making an object always takes new (Topic 1.13). The call copies an address, so the method and main work on one object, and the program prints Back in main: 15. When you trace, ask “which object does this variable lead to?” rather than “which variable is this?”

Pause and try

Question 1 · Tracing

Write the exact output.

DoubleUp.java
public class DoubleUp
{
    public static void main(String[] args)
    {
        Player grace = new Player("Grace", 4);
        Coach coach = new Coach();
        coach.doubleUp(grace);
        coach.doubleUp(grace);
        System.out.println(grace.getPoints());
    }
}

class Coach
{
    public void doubleUp(Player p)
    {
        p.addPoints(p.getPoints());
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Check your reasoning
16

grace refers to one Player object that starts with 4 points. Each call copies that reference into p, so p leads to the same object.

Call p.getPoints() before line 17 addPoints adds Points afterward
First (line 7) 4 4 8
Second (line 8) 8 8 16

The second call sees 8, not 4, because the first call already changed the shared object. Line 9 prints 16.

Reread 3.6.1 Passing an Object Reference if your output differed.

Question 2 · Multiple choice

In BonusByReference, what does the parameter p hold while awardBonus runs?

  1. A new Player object with the same name and points as star’s object
  2. A copy of the reference stored in star, so p and star lead to the same object
  3. A copy of the points value, 10
  4. The variable star itself, so assigning to p would also change star
Check your reasoning

B. A parameter is initialized with a copy of its argument, and the argument star holds a reference. So p holds a copy of that reference, and both lead to one object.

  • A is wrong: no new runs during the call, so no second object exists. This is the “method gets a photocopy of the object” misconception.
  • C is wrong: the parameter’s type is Player, not int. The method can get the points by calling p.getPoints(), but p itself holds a reference.
  • D is wrong: p is a separate variable that holds a copy of the address. Assigning a different object to p would change only p, as 3.6.2 shows.

Reread 3.6.1 Passing an Object Reference if you chose differently.

Section 2 of 5

3.6.2 What a Method Cannot Change

If a method can change the caller’s object, can it also make the caller’s variable refer to a different object? Suppose a reset method tries to replace a player with a brand-new rookie. Does the caller end up with the rookie?

The address slip from 3.6.1 answers it. The parameter is the method’s own slip. Following the slip to the house and painting the door changes the house everyone shares. Erasing the slip and writing a new address on it changes only that slip. The caller’s slip still has the old address.

In Java terms, there are two very different things a method can do with an object parameter:

Statement in the method What it changes Does the caller see it?
p.addPoints(5); The object p refers to Yes, the caller refers to that object too
p = new Player("Rookie", 0); The parameter p (which address it holds) No, the caller’s variable still holds the old address

The dot in p.addPoints means “go to the object and act on it.” An assignment p = … means “put a different address in p.” Only the first one reaches the shared object.

Key idea

Assigning a new reference to a parameter changes only the parameter. The caller’s variable keeps referring to the same object it did before the call.

Worked example: Replacing the parameter

Line 16 assigns a new object to p. Watch what star refers to before and after.

ReplaceParameter.java
public class ReplaceParameter
{
    public static void main(String[] args)
    {
        Player star = new Player("Ada", 10);
        Scorekeeper keeper = new Scorekeeper();
        keeper.reset(star);
        System.out.println("Back in main: " + star.getName() + " " + star.getPoints());
    }
}

class Scorekeeper
{
    public void reset(Player p)
    {
        p = new Player("Rookie", 0);
        System.out.println("Inside reset: " + p.getName() + " " + p.getPoints());
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}

Line 7 copies star’s reference, “address A,” into p. Then line 16 runs. The right side, new Player("Rookie", 0), builds a second object at “address B” and the = stores address B in p:

Variable Holds Object at that address
star (in main) reference to address A Player “Ada”, 10 points
p (in reset) reference to address B Player “Rookie”, 0 points

Line 17 follows p to address B and prints Inside reset: Rookie 0. When the method ends, p disappears. Nothing holds address B anymore, so the rookie is lost. star never stopped holding address A, so line 8 prints Ada’s unchanged data.

Inside reset: Rookie 0
Back in main: Ada 10

The same rule explains what happens with a String parameter. A String is immutable (Topic 1.15): it has no mutators, so a method cannot change the text of the object it receives. All it can do is build a new string and store that in its parameter.

CheerString.java
public class CheerString
{
    public static void main(String[] args)
    {
        String cheer = "Go team";
        Announcer announcer = new Announcer();
        announcer.shout(cheer);
        System.out.println("Back in main: " + cheer);
    }
}

class Announcer
{
    public void shout(String text)
    {
        text = text + "!!!";
        System.out.println("Inside shout: " + text);
    }
}
Inside shout: Go team!!!
Back in main: Go team

Line 16 builds a new String, "Go team!!!", and moves text to it. That is an assignment to the parameter, like line 16 of ReplaceParameter, so cheer in main still refers to the original "Go team". A method can change the state of a mutable object passed to it, but it can never change a String argument.

Watch out

Trying to swap two objects by swapping parameters. This method is meant to make first and second trade players:

SwapPlayersWrong.java
public class SwapPlayersWrong
{
    public static void main(String[] args)
    {
        Player first = new Player("Ada", 10);
        Player second = new Player("Grace", 20);
        Scorekeeper keeper = new Scorekeeper();
        keeper.swap(first, second);
        System.out.println("first: " + first.getName());
        System.out.println("second: " + second.getName());
    }
}

class Scorekeeper
{
    public void swap(Player a, Player b)
    {
        Player temp = a;
        a = b;
        b = temp;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
first: Ada
second: Grace

Nothing traded. Lines 18 to 20 swap the addresses held by a and b, which are the method’s own copies. first and second in main were never assigned, so they still refer to Ada and Grace. Students write this because the three-step swap with temp works on ordinary variables in one place. It cannot work across a method call, because a method has no way to put a new address into the caller’s variables. A method only affects the caller through the objects it changes with mutators, or through a value it returns (3.6.4).

Pause and try

Question 3 · Tracing

Write the exact output.

MixedUpdate.java
public class MixedUpdate
{
    public static void main(String[] args)
    {
        Player kai = new Player("Kai", 10);
        Scorekeeper keeper = new Scorekeeper();
        keeper.update(kai);
        System.out.println(kai.getName() + " " + kai.getPoints());
    }
}

class Scorekeeper
{
    public void update(Player p)
    {
        p.addPoints(3);
        p = new Player("Temp", 100);
        p.addPoints(3);
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Check your reasoning
Kai 13
Line p refers to Kai’s object “Temp” object
7 Kai’s object (address A) 10 points (none yet)
16 Kai’s object 13 points (none yet)
17 “Temp” object (address B) 13 points 100 points
18 “Temp” object 13 points 103 points

Line 16 runs while p still refers to Kai’s object, so Kai gets 3 points. Line 17 moves p to a new object, so line 18 adds 3 to “Temp”, not to Kai. kai in main still refers to address A, so line 8 prints Kai 13.

Reread 3.6.2 What a Method Cannot Change if your output differed.

Question 4 · Short answer

A classmate wants a method that adds an exclamation point to the caller’s String so that the caller’s variable shows the new text after the call. Explain why no method with a String parameter can do this.

Check your reasoning

Model answer: The method’s parameter holds a copy of the reference to the caller’s String. A String is immutable, so there is no method that changes the text of that object. The only way to get new text is to build a new String and assign it to the parameter, but assigning to a parameter changes only the parameter, not the caller’s variable. So the caller’s variable still refers to the original, unchanged text.

A complete answer mentions both ideas:

  • Strings are immutable, so the shared object cannot be changed.
  • Assigning a new string to the parameter does not change the caller’s variable.

(The method could return the new string, and the caller could store it, which is how String methods like substring work.)

Reread 3.6.2 What a Method Cannot Change if your answer differed.

Section 3 of 5

3.6.3 Leave Parameters Unchanged Unless Asked

Being able to change a caller’s object is powerful, and it is also a trap. Someone who calls a method named previewBonus expects to see a number, not to have their player’s score changed. If a method quietly changes an object passed to it, the caller has no hint from the call itself, and the bug shows up later somewhere else.

A method’s specification is the description of what it is supposed to do, often written as a comment just above its header. Callers rely on the specification instead of reading the method’s code. Recall from Topic 3.5 that accessors report information while mutators change it. The good-practice rule follows: a method or constructor should not modify a mutable object passed as a parameter unless its specification says to. If the job is to report, compute, or record something, the method should read the object through its accessors and leave it alone. If the job is to change the object, as with awardBonus, changing it is exactly right.

A changed parameter object that the caller did not ask for is called a side effect. It is legal Java, so the compiler never complains. Only careful reading of the specification catches it.

Key idea

Do not change an object passed to a method or constructor unless the specification requires that change. Read it with accessors instead.

Watch out

A “preview” that changes the player. The comment on line 15 is the specification: report what the total would be.

PreviewChanges.java
public class PreviewChanges
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 10);
        Scorekeeper keeper = new Scorekeeper();
        System.out.println(keeper.previewBonus(ada, 5));
        System.out.println(keeper.previewBonus(ada, 5));
        System.out.println(ada.getPoints());
    }
}

class Scorekeeper
{
    // Returns what p's total would be if p earned bonus more points.
    public int previewBonus(Player p, int bonus)
    {
        p.addPoints(bonus);
        return p.getPoints();
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
15
20
20

The first call prints 15, which looks right. But line 18 actually added 5 to Ada’s object, so the second call starts from 15 and prints 20, and Ada now really has 20 points. The method does more than its specification promises. Students write it this way because “add the bonus, then get the total” is how they would do it on paper. The fix computes the answer without touching the object:

return p.getPoints() + bonus;

With that single line as the method body, the program prints 15, 15, and 10: the preview is the same every time, and Ada keeps her 10 points.

Constructors follow the same rule, because a constructor’s parameters are initialized the same way. This Team constructor is specified only to record the captain’s name, but line 19 also changes the Player it was given:

WelcomeBonus.java
public class WelcomeBonus
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 10);
        Team robots = new Team(ada);
        System.out.println(robots.getCaptainName() + " has " + ada.getPoints());
    }
}

class Team
{
    private String captainName;

    // Records the name of the team's captain.
    public Team(Player captain)
    {
        captainName = captain.getName();
        captain.addPoints(10);
    }

    public String getCaptainName()
    {
        return captainName;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Ada has 20

Line 6 passes ada’s reference to the constructor, so captain and ada refer to the same object. Line 18 reads the name with an accessor, which is fine. Line 19 calls a mutator on the shared object, so Ada’s points jump from 10 to 20 just because a team was created. Deleting line 19 makes the constructor match its specification, and the program would print Ada has 10.

Pause and try

Question 5 · Debugging

The specification on line 15 says the method returns the total of the two players’ points. The returned total is correct, but the method has a side effect. Identify the problem and write a corrected method body.

CombinedBug.java
public class CombinedBug
{
    public static void main(String[] args)
    {
        Player lee = new Player("Lee", 8);
        Player mia = new Player("Mia", 6);
        Scorekeeper keeper = new Scorekeeper();
        System.out.println(keeper.combinedPoints(lee, mia));
        System.out.println(lee.getPoints());
    }
}

class Scorekeeper
{
    // Returns the total points of players a and b.
    public int combinedPoints(Player a, Player b)
    {
        a.addPoints(b.getPoints());
        return a.getPoints();
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Check your reasoning

The program prints 14 and then 14. The total is right, but line 18 adds Mia’s points to Lee’s object, so Lee now has 14 points instead of 8. Because a holds a copy of lee’s reference, the mutator call changes the caller’s object, which the specification never asked for.

Corrected body:

return a.getPoints() + b.getPoints();

Now the method only reads both objects through accessors. The program prints 14 and then 8.

Reread 3.6.3 Leave Parameters Unchanged Unless Asked if your fix differed.

Question 6 · Short answer

A Scorekeeper method has this specification: “Moves amount points from giver to receiver.” Its body calls giver.addPoints(-amount) and receiver.addPoints(amount). Is this method breaking the good-practice rule about changing parameters? Explain.

Check your reasoning

Model answer: No. The rule is to avoid changing a parameter’s object unless the specification requires it. Here, changing both players’ points is the method’s whole job, so the changes are exactly what callers expect. They are not side effects.

A complete answer says that the rule depends on the specification, and that this specification asks for both objects to change.

Reread 3.6.3 Leave Parameters Unchanged Unless Asked if your answer differed.

Section 4 of 5

3.6.4 Returning a Reference

Sometimes a method’s answer is an object: “which of these two players is ahead?” In Topic 3.5, a non-void method evaluated its return expression and handed back a copy of the value, so returning an int gave the caller a number of its own. What does the caller get when the return type is a class, such as Player?

The same thing happens as with parameters. The return expression evaluates to a reference, and that reference is what gets copied back to the caller. The object itself is not copied. If the method returns a reference to an object that already exists, the caller’s variable becomes another alias of that object.

Key idea

When a method returns an object, it returns a reference to that object, not a new copy of it. The caller and anyone else holding that reference share one object.

Worked example: The leader is not a copy

leader returns one of its two parameters. Watch what top refers to after line 8.

LeaderReturn.java
public class LeaderReturn
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 12);
        Player grace = new Player("Grace", 9);
        Scorekeeper keeper = new Scorekeeper();
        Player top = keeper.leader(ada, grace);
        top.addPoints(1);
        System.out.println(top.getName() + " " + top.getPoints());
        System.out.println(ada.getName() + " " + ada.getPoints());
        System.out.println(top == ada);
    }
}

class Scorekeeper
{
    // Returns whichever player has more points (a if they are tied).
    public Player leader(Player a, Player b)
    {
        if (b.getPoints() > a.getPoints())
        {
            return b;
        }
        return a;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}

Lines 5 and 6 build Ada (address A, 12 points) and Grace (address B, 9 points). Line 8 copies address A into a and address B into b. In leader, line 21 asks whether 9 > 12, which is false, so line 25 runs return a;. The value of the expression a is “address A,” and that is what comes back and gets stored in top:

Variable Holds Object at that address
ada reference to address A Player “Ada”, 12 points
grace reference to address B Player “Grace”, 9 points
top reference to address A (the same object as ada)

Line 9 adds 1 point through top, which changes Ada’s object to 13 points. Lines 10 and 11 reach that same object through two different variables. Line 12 compares the two references with == (Topic 2.6), which is true because they hold the same address.

Ada 13
Ada 13
true

Now vary it: the method returns an instance variable instead of a parameter. This Team builds its own private Player in its constructor, and getCaptain returns it.

CaptainLeak.java
public class CaptainLeak
{
    public static void main(String[] args)
    {
        Team robots = new Team("Ada");
        Player c = robots.getCaptain();
        c.addPoints(50);
        System.out.println("Team says: " + robots.getCaptainPoints());
    }
}

class Team
{
    private Player captain;

    public Team(String captainName)
    {
        captain = new Player(captainName, 0);
    }

    public Player getCaptain()
    {
        return captain;
    }

    public int getCaptainPoints()
    {
        return captain.getPoints();
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Team says: 50

Line 23 returns the reference stored in the private instance variable captain. Line 6 stores that reference in c, so c and the team’s captain are aliases. Line 7 adds 50 points through c, and the team’s own captain object changes, even though Team has no method for changing its captain’s points. Making captain private kept other classes from writing robots.captain, but it did not protect the object once a reference to it was handed out.

If the class designer does not want outside code to change the team’s captain, getCaptain can build and return a new object with the same data:

return new Player(captain.getName(), captain.getPoints());

With that line as the body of getCaptain, line 7 changes only the copy, and the program prints Team says: 0. This is the return-side partner of the Topic 3.4 advice to store a copy of a mutable object that a constructor receives.

Watch out

Expecting return to hand back a copy. It is tempting to think that a variable like top or c holds “the answer” and is safe to change. It is not a copy unless the method made one with new. return captain; and return a; hand back an existing object’s address, so changes through the returned reference show up everywhere that object is used. If you need an independent object, the method must build one, as in the fix above.

Pause and try

Question 7 · Tracing

leader is the same method as in LeaderReturn: it returns b only when b has more points, and otherwise returns a. Write the exact output.

LeaderTie.java
public class LeaderTie
{
    public static void main(String[] args)
    {
        Player lee = new Player("Lee", 7);
        Player mia = new Player("Mia", 7);
        Scorekeeper keeper = new Scorekeeper();
        Player top = keeper.leader(lee, mia);
        top.addPoints(2);
        Player next = keeper.leader(mia, lee);
        next.addPoints(1);
        System.out.println(lee.getPoints() + " " + mia.getPoints());
        System.out.println(top == next);
    }
}

class Scorekeeper
{
    // Returns whichever player has more points (a if they are tied).
    public Player leader(Player a, Player b)
    {
        if (b.getPoints() > a.getPoints())
        {
            return b;
        }
        return a;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Check your reasoning
10 7
true
Line What happens Lee Mia
8 leader(lee, mia): is 7 > 7? No, so it returns a, Lee’s reference 7 7
9 top refers to Lee, so Lee gets 2 9 7
10 leader(mia, lee): now a is Mia, b is Lee. Is 9 > 7? Yes, so it returns b, Lee’s reference 9 7
11 next refers to Lee, so Lee gets 1 10 7

Both calls returned a reference to Lee’s object, so top == next is true. No call created a new object.

Reread 3.6.4 Returning a Reference if your output differed.

Question 8 · Multiple choice

In CaptainLeak, which replacement for line 23 keeps lines 6 and 7 from changing the team’s own captain?

  1. Player backup = new Player(captain.getName(), captain.getPoints()); return captain;
  2. Player result = captain; return result;
  3. return new Player(captain.getName(), captain.getPoints());
  4. return captain.getPoints();
Check your reasoning

C. It builds a new Player object with the captain’s data and returns a reference to that new object. Line 7 then changes the copy, and the team’s captain keeps 0 points.

  • A is wrong: it builds a copy but then returns captain, the team’s own reference. The copy is never used, so the program still prints Team says: 50. Making a copy helps only if the copy is what gets returned.
  • B is wrong: result = captain copies the address, not the object. result is an alias, so the same reference comes back. This is the “assignment makes a copy” misconception, and the program still prints Team says: 50.
  • D is wrong: it returns an int, which does not match the return type Player, so the method does not compile.

Reread 3.6.4 Returning a Reference if you chose differently.

Section 5 of 5

3.6.5 Private Data of a Parameter

Suppose Player needs a method that answers “is this player ahead of that one?” The method receives another Player as a parameter. Inside Player, can it read other.points directly, or must it call other.getPoints()? And what about a Scorekeeper method that receives a Player?

From Topic 3.3, private restricts access to the declaring class. The key word is class, not object. Code written inside the Player class may use the private instance variables and private methods of any Player object it has a reference to, not only the object it was called on. Code in any other class may not, even when it holds a perfectly good reference to a Player.

Why draw the line at the class? private exists to hide how a class works from code written outside it (encapsulation). Code inside Player is already part of that hidden design: whoever writes Player knows what points means and keeps it correct for every Player object. Code in Scorekeeper is outside, so it must go through the public methods.

Key idea

A method can use the private data and private methods of an object passed to it only when the parameter’s type is the same class the method is written in. Every other class must use public methods such as accessors.

Worked example: Comparing with another player

isAheadOf is written inside Player and receives another Player.

AheadOf.java
public class AheadOf
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 12);
        Player grace = new Player("Grace", 9);
        System.out.println(ada.isAheadOf(grace));
        System.out.println(grace.isAheadOf(ada));
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public boolean isAheadOf(Player other)
    {
        return points > other.points;
    }
}

On line 7, ada.isAheadOf(grace) runs the method for Ada’s object, with other holding a reference to Grace’s object. On line 25, points with no dot means the points of the object the method was called on, Ada’s 12. other.points follows other to Grace’s object and reads its private points, 9. Because the method is in Player and other is a Player, the compiler allows it. 12 > 9 is true. Line 8 reverses the roles: 9 > 12 is false.

true
false

The rule covers private methods too. Here hasScored is private, and bothScored, also inside Player, calls it on itself and on the parameter:

BothScored.java
public class BothScored
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 12);
        Player kai = new Player("Kai", 0);
        System.out.println(ada.bothScored(kai));
        System.out.println(ada.bothScored(ada));
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public boolean bothScored(Player other)
    {
        return hasScored() && other.hasScored();
    }

    private boolean hasScored()
    {
        return points > 0;
    }
}
false
true

Line 7: Ada has 12 points but Kai has 0, so other.hasScored() is false and the result is false. Line 8 passes ada as the argument to her own method, so both calls check the same object, and the result is true.

Watch out

Reaching into private data from a different class. Scorekeeper holds a reference to a Player, so it seems like it should be able to read the points:

PrivateFromOutside.java
public class PrivateFromOutside
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 12);
        Scorekeeper keeper = new Scorekeeper();
        System.out.println(keeper.pointsOf(ada));
    }
}

class Scorekeeper
{
    public int pointsOf(Player p)
    {
        return p.points;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public int getPoints()
    {
        return points;
    }
}

This does not compile. Java reports something like this (the wording can vary between Java versions):

PrivateFromOutside.java:15: error: points has private access in Player

The method is in Scorekeeper, but the parameter’s type is Player, a different class, so its private variables are off limits. The fix is to use the public accessor: change line 15 to return p.getPoints();, and the program prints 12.

Pause and try

Question 9 · Multiple choice

SameScoreAccess does not compile. Which line causes the error?

SameScoreAccess.java
public class SameScoreAccess
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 12);
        Player kai = new Player("Kai", 12);
        Coach coach = new Coach();
        System.out.println(ada.sameScore(kai));
        System.out.println(coach.sameName(ada, kai));
    }
}

class Coach
{
    public boolean sameName(Player p, Player q)
    {
        return p.name.equals(q.name);
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public boolean sameScore(Player other)
    {
        return points == other.points;
    }
}
  1. Line 8, because kai is passed to a method of a different object
  2. Line 17, because Coach uses the private name of its Player parameters
  3. Line 34, because sameScore uses the private points of its parameter other
  4. Both line 17 and line 34, because private data can be used only for the object a method is called on
Check your reasoning

B. sameName is written in Coach, but p and q are Player references, a different class, so p.name and q.name are not allowed. Java reports name has private access in Player.

  • A is wrong: passing a reference to any method is always allowed; access rules are about what code may use once it has the reference.
  • C is wrong: sameScore is written inside Player and its parameter is a Player, so other.points is allowed.
  • D is wrong: private is about the class the code is in, not about which object. This choice comes from thinking each object guards its own private data from every other object.

Reread 3.6.5 Private Data of a Parameter if you chose differently.

Wrap-up · 1 of 5

Putting it together

This program uses every idea in the chapter. trade changes both of its parameters (its specification says to) and returns a reference. resetToZero tries to replace its parameter. isAheadOf reads a parameter’s private data from inside Player.

TradeDay.java
public class TradeDay
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 20);
        Player grace = new Player("Grace", 12);
        Scorekeeper keeper = new Scorekeeper();
        Player leader = keeper.trade(ada, grace, 5);
        leader.addPoints(2);
        keeper.resetToZero(ada);
        System.out.println("Ada: " + ada.getPoints());
        System.out.println("Grace: " + grace.getPoints());
        System.out.println(leader == grace);
        System.out.println(grace.isAheadOf(ada));
    }
}

class Scorekeeper
{
    // Moves amount points from giver to receiver.
    // Returns whichever player is ahead afterward (giver if tied).
    public Player trade(Player giver, Player receiver, int amount)
    {
        giver.addPoints(-amount);
        receiver.addPoints(amount);
        if (receiver.getPoints() > giver.getPoints())
        {
            return receiver;
        }
        return giver;
    }

    // Meant to set p's points to 0 (it does not work).
    public void resetToZero(Player p)
    {
        p = new Player(p.getName(), 0);
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }

    public boolean isAheadOf(Player other)
    {
        return points > other.points;
    }
}

Ada’s object is at address A and Grace’s at address B.

Line(s) What happens Ada Grace leader
5–6 Two objects are built 20 12
8, 24–25 giver gets address A, receiver gets address B; mutators change both shared objects 15 17
26–28 17 > 15 is true, so it returns receiver, address B, stored in leader 15 17 B
9 leader is an alias of Grace, so Grace gets 2 15 19 B
10, 36 p gets address A, then is moved to a new 0-point object; the new object is lost when the method ends 15 19 B
11–12 Print both totals 15 19 B
13 leader and grace both hold address B 15 19 B
14 Inside Player, points > other.points is 19 > 15 15 19 B
Ada: 15
Grace: 19
true
true

Notice the two methods that receive Ada. trade used a mutator through its parameter, and the change stuck. resetToZero assigned to its parameter, and nothing changed for the caller. To actually reset a player, Player would need a mutator that sets points to 0, and resetToZero would call it.

Wrap-up · 2 of 5

Vocabulary

Term Definition Example
mutable Describes an object whose state can be changed after it is created, usually through mutators A Player with addPoints
specification A description of what a method or class is supposed to do, which callers rely on “Returns the total of the two players’ points”
side effect A change a method makes to an object passed to it (or other state) that its specification does not call for previewBonus adding points to p
reference (review) The address of an object, which is what a variable of a class type holds star holds “address A”
alias (review) One of two or more variables that refer to the same object p and star during awardBonus(star)
Wrap-up · 3 of 5

Chapter summary

  • When the argument is an object, the parameter gets a copy of the reference. No new object is made, so the parameter and the caller’s variable refer to the same object.
  • Calling a mutator through the parameter changes the shared object, and the caller sees the change. Assigning a new reference to the parameter changes only the parameter, and the caller sees nothing. A String argument can never be changed, because strings are immutable.
  • A method or constructor should not change a mutable object it receives unless its specification calls for that change; otherwise it should only read the object with accessors.
  • Returning an object returns a reference to it, not a copy. Returning a private instance variable’s reference lets outside code change that object; returning a new object built with new prevents this.
  • Code may use the private variables and private methods of a parameter only when the parameter’s type is the class the code is written in.
Wrap-up · 4 of 5

Review questions

Question 10 · Multiple choice

This Team constructor stores the Player it receives. What does the program print?

StoredReference.java
public class StoredReference
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 10);
        Team robots = new Team(ada);
        ada.addPoints(5);
        System.out.println(robots.getCaptainPoints());
    }
}

class Team
{
    private Player captain;

    public Team(Player firstCaptain)
    {
        captain = firstCaptain;
    }

    public int getCaptainPoints()
    {
        return captain.getPoints();
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
  1. 10, because the team made its own copy of Ada when it was built
  2. 15, because captain and ada refer to the same object
  3. 5, because only the change after line 6 counts
  4. Nothing; a constructor cannot receive an object as a parameter
Check your reasoning

B. Line 6 copies ada’s reference into firstCaptain, and line 18 copies it again into the instance variable captain. No new Player runs, so there is one object. Line 7 adds 5 points to it through ada, and getCaptainPoints reads that same object: 15.

  • A is wrong: making a copy takes new. Line 18 copies only the address. This is the advice from Topic 3.4 that the constructor did not follow.
  • C is wrong: addPoints adds to the existing 10 points; it does not start the total over.
  • D is wrong: constructors receive object references exactly the way methods do.

Reread 3.6.1 Passing an Object Reference if you chose differently.

Question 11 · Tracing

Write the exact output.

PickTrace.java
public class PickTrace
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 5);
        Player bo = new Player("Bo", 5);
        Scorekeeper keeper = new Scorekeeper();
        Player result = keeper.pick(ada, bo);
        result.addPoints(100);
        System.out.println(ada.getPoints());
        System.out.println(bo.getPoints());
        System.out.println(result == bo);
    }
}

class Scorekeeper
{
    public Player pick(Player p, Player q)
    {
        p.addPoints(1);
        p = q;
        p.addPoints(10);
        return p;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
Check your reasoning
6
115
true

Ada’s object is address A, Bo’s is address B.

Line p refers to Ada Bo Notes
8 A 5 5 p gets A, q gets B
20 A 6 5 Mutator through p changes Ada
21 B 6 5 Only p changes; ada still holds A
22 B 6 15 Mutator through p now changes Bo
23 B 6 15 Returns address B, stored in result
9 6 115 result is an alias of Bo

Line 12 compares two references that both hold address B, so it prints true.

Reread 3.6.2 What a Method Cannot Change and 3.6.4 Returning a Reference if your output differed.

Question 12 · Debugging

Shop’s refund method is supposed to add amount dollars to the customer’s wallet, but the program does not compile. Explain the error and correct line 17.

ShopRefund.java
public class ShopRefund
{
    public static void main(String[] args)
    {
        Wallet mine = new Wallet(20);
        Shop shop = new Shop();
        shop.refund(mine, 5);
        System.out.println(mine.getDollars());
    }
}

class Shop
{
    // Gives amount dollars back to the customer's wallet.
    public void refund(Wallet w, int amount)
    {
        w.dollars = w.dollars + amount;
    }
}

class Wallet
{
    private int dollars;

    public Wallet(int startDollars)
    {
        dollars = startDollars;
    }

    public int getDollars()
    {
        return dollars;
    }

    public void addDollars(int amount)
    {
        dollars = dollars + amount;
    }
}
Check your reasoning

Java reports dollars has private access in Wallet for line 17. refund is written in Shop, but w is a Wallet, a different class, so Shop code may not use w.dollars.

Corrected line 17:

w.addDollars(amount);

addDollars is a public mutator of Wallet, so Shop may call it. Because w holds a copy of mine’s reference, the change reaches the caller’s wallet, and the program prints 25. Changing the wallet here is fine: the specification on line 14 asks for it.

Reread 3.6.5 Private Data of a Parameter if your fix differed.

Question 13 · Multiple choice

A student wrote makeCopy to give main a backup of a player. What does the program print?

FakeCopy.java
public class FakeCopy
{
    public static void main(String[] args)
    {
        Player ada = new Player("Ada", 10);
        Scorekeeper keeper = new Scorekeeper();
        Player backup = keeper.makeCopy(ada);
        backup.addPoints(5);
        System.out.println(ada.getPoints());
    }
}

class Scorekeeper
{
    public Player makeCopy(Player p)
    {
        Player result = p;
        return result;
    }
}

class Player
{
    private String name;
    private int points;

    public Player(String playerName, int startPoints)
    {
        name = playerName;
        points = startPoints;
    }

    public String getName()
    {
        return name;
    }

    public int getPoints()
    {
        return points;
    }

    public void addPoints(int amount)
    {
        points = points + amount;
    }
}
  1. 10, because backup is a separate copy of Ada
  2. 15, because makeCopy returns the same reference it received
  3. 5, because backup starts with 0 points
  4. Nothing; a method cannot return a parameter
Check your reasoning

B. Line 7 copies ada’s reference into p. Line 17 copies it into result, and line 18 returns it. No new ever runs, so backup, result, p, and ada all refer to the one object. Line 8 adds 5 to it, and line 9 prints 15.

  • A is wrong: neither the call, the assignment on line 17, nor return copies an object. Only new makes one.
  • C is wrong: no new Player is constructed, so nothing starts at 0.
  • D is wrong: returning a parameter is allowed whenever its type matches the return type, as leader did in 3.6.4.

To make a real backup, replace lines 17 and 18 with return new Player(p.getName(), p.getPoints());. Then backup refers to a new object, and the program prints 10.

Reread 3.6.4 Returning a Reference if you chose differently.

Question 14 · Short answer

A classmate says: “When you pass an object to a method, the method gets the actual variable, so it can do anything to the caller’s variable, including making it refer to a different object.” Using BonusByReference and ReplaceParameter from this chapter, explain what part of that claim is right and what part is wrong.

Check your reasoning

Model answer: The method does get access to the caller’s object, because the parameter holds a copy of the same reference. That is why awardBonus in BonusByReference could add 5 points and main saw 15. But the method does not get the caller’s variable. The parameter is a separate variable holding a copy of the address. In ReplaceParameter, reset stored a new object in p, and star in main still referred to Ada with 10 points. So a method can change the caller’s mutable object, but it can never make the caller’s variable refer to a different object.

A complete answer includes:

  • The parameter holds a copy of the reference, so it reaches the same object, and mutators change it for the caller.
  • The parameter is a separate variable, so assigning to it does not change the caller’s variable.

Reread 3.6.1 Passing an Object Reference and 3.6.2 What a Method Cannot Change if your answer differed.

Wrap-up · 5 of 5

Reflection

  • I can explain what a parameter holds when the argument is an object, and why no new object is made. Reread
  • I can predict whether a change made inside a method shows up for the caller. Reread
  • I can spot a method or constructor that changes a parameter object its specification does not mention. Reread
  • I can trace a method that returns an object and explain why the caller gets the same object, not a copy. Reread
  • I can decide whether a method may use the private data of an object passed to it. Reread