Skip to content
HopperHopper

Course navigation

Unit 3 · Class CreationTopic 3.4

Constructors

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

Before you start

About 55 minutes

By the end you will be able to

  1. Describe an object's state as the values of its instance variables at a given moment, and explain the has-a relationship.
  2. Write the header and body of a constructor that gives every instance variable a starting value.
  3. Explain what happens in memory when a constructor is called and what the call hands back.
  4. Use constructor parameters, with names different from the instance variables, to supply starting values.
  5. State the default values Java gives instance variables and explain when Java supplies a default constructor.
  6. Explain why a constructor should store a copy of a mutable object it receives instead of the object itself.

What to remember from earlier

Section 1 of 5

3.4.1 Object State and Instance Variables

Picture two library books sitting on a cart. Both are books, built from the same blueprint, but one is Holes with 233 pages and is checked out, and the other is Wonder with 310 pages and is on the shelf. If a program is going to keep track of books, it has to remember those facts separately for each one. Where does each book keep its own facts?

Recall from Topic 1.12 that the facts a class’s objects keep track of are called attributes, and from Topic 3.3 that each attribute is stored in an instance variable: a variable declared inside the class but outside any constructor or method, so that every object gets its own copy. Here is a Book class with three attributes:

public class Book
{
    private String title;
    private int pages;
    private boolean checkedOut;
}

Each instance variable has a type and a name, like any variable from Topic 1.2, and private keeps it inside the class (Topic 3.3). The class only describes which facts a book keeps. The values themselves live in each object.

The set of values an object’s instance variables hold at a particular moment is the object’s state. “At a particular moment” matters: if Holes is returned, its checkedOut value changes from true to false, and its state is now different, even though it is the same object.

Worked example: The state of two Book objects

Suppose a program has built two Book objects. Each one has its own three boxes:

Instance variable State of the first book State of the second book
title "Holes" "Wonder"
pages 233 310
checkedOut true false

Read down a column to get one object’s state. The two objects share the same instance variables (the same three names and types, from the class) but have different values, so they have different states. Changing the first book’s checkedOut would not touch the second book’s, because each object has its own copy.

Now vary the moment instead of the object. Take a single Thermostat object whose instance variables are double temperature and boolean heating:

Time temperature heating State
7:00 AM 17.5 true cold, heater on
9:00 AM 21.0 false comfortable, off

It is one object the whole time; its state at 7:00 differs from its state at 9:00 because the values changed. (The methods that change an object’s state after it is built are Topic 3.5. This chapter is about the very first state an object has.)

Because the instance variables belong to the object, programmers describe the connection with the words “has a”: a book has a title, has a page count, and has a checked-out status. This is called a has-a relationship between an object and its instance variables. It is a handy test when you design a class: if you can say “a _ has a _,” the second blank is a good candidate for an instance variable.

Key idea

An object’s state is the set of values its instance variables hold at a given moment. The instance variables belong to the object, which gives a has-a relationship: a book has a title.

Watch out

Mixing up the instance variables with the state. The instance variables (title, pages, checkedOut) come from the class and are the same for every Book. The state is the values in them, which differ from object to object and can change over time. “Every book has a pages variable” is about the class; “this book’s pages is 233” is about one object’s state.

Pause and try

Question 1 · Multiple choice

A class Song has the instance variables String title, int seconds, and boolean favorite. Which sentence describes a has-a relationship in this class?

  1. A song has a favorite status.
  2. A song has a Song class.
  3. A title has a song.
  4. A song has a Book.
Check your reasoning

A. In a has-a relationship, the object has each of its instance variables. favorite is an instance variable of Song, so “a song has a favorite status” fits.

  • B is wrong: the class is the blueprint the object is built from, not something stored inside the object.
  • C is wrong: it reverses the relationship. The object has the attribute, not the other way around.
  • D is wrong: Song has no instance variable for a book.

Reread 3.4.1 Object State and Instance Variables if you chose differently.

Question 2 · Short answer

At noon, a Song object holds title = "Lift", seconds = 214, and favorite = false. At 3:00 the listener marks it as a favorite. Is it still the same object? Has its state changed? Explain.

Check your reasoning

Model answer: It is the same object, because no new object was built; one of its instance variables just got a new value. Its state has changed: at noon the values were "Lift", 214, false, and at 3:00 they are "Lift", 214, true. State means the values at a given moment, so changing any one value changes the state.

A complete answer must:

  • say it is the same object, and
  • say the state changed because favorite now holds a different value.

Reread 3.4.1 Object State and Instance Variables if your answer differed.

Section 2 of 5

3.4.2 Writing a Constructor

The Book class above declares three instance variables but never puts anything in them. When a program writes new Book(...), which code decides that this book is Holes with 233 pages? In Topic 1.13 you only called constructors that someone else wrote. Now you write one.

A constructor sets the initial state of a new object: the values its instance variables hold at the moment it is created. A well-written constructor gives a starting value to every instance variable, so the object never begins life half-filled-in.

Here is the shape of a constructor, written inside the class after the instance variables:

public Book(String bookTitle, int pageCount)
{
    title = bookTitle;
    pages = pageCount;
    checkedOut = false;
}
Piece What it is and why it is there
public Lets code in other classes call it. In this course constructors are always public (Topic 3.3)
Book Exactly the class name, capital letter included; that is how Java recognizes a constructor
(nothing before the name) No return type, not even void; a constructor always produces an object of its own class
(String bookTitle, int pageCount) The parameter list: the values a caller must pass in, as in Topic 1.13
{ ... } The body: ordinary statements that run when the constructor is called
title = bookTitle; and the others Assignments (Topic 1.4) that store a starting value in each instance variable

The body is where the instance variables get filled in. Inside a constructor you refer to an instance variable just by its name, title, and Java knows you mean the title of the object being built.

What actually happens when new Book("Holes", 233) runs? Three things, in order:

  1. Memory is set aside for a brand-new Book object, with room for its own title, pages, and checkedOut.
  2. The constructor body runs for that new object, with bookTitle holding a copy of "Holes" and pageCount a copy of 233. Its assignments fill in the instance variables.
  3. A reference to the new object is handed back as the value of the whole new expression, so it can be stored in a variable.

Key idea

A constructor has the class name and no return type. Calling it with new sets aside memory for a new object, runs the body to give every instance variable a starting value, and returns a reference to the object.

Worked example: Building a Book

Two classes share this file so it runs as one program. (In a real project each class goes in its own file and is marked public; Java allows only one public class per file, so the helper class here leaves the word off.) Instance variables are private, and writing methods that report them is Topic 3.5, so for now the constructor prints the state it just set with println, using string concatenation from Topic 1.15.

BookCreation.java
public class BookCreation
{
    public static void main(String[] args)
    {
        System.out.println("Before the call");
        Book novel = new Book("Holes", 233);
        System.out.println("After the call");
    }
}

class Book
{
    private String title;
    private int pages;
    private boolean checkedOut;

    public Book(String bookTitle, int pageCount)
    {
        title = bookTitle;
        pages = pageCount;
        checkedOut = false;
        System.out.println(title + ", " + pages + " pages, checked out: " + checkedOut);
    }
}
Order Line What happens
1 5 Prints Before the call
2 6 new sets aside memory for a Book with its own title, pages, and checkedOut
3 17 The constructor starts: bookTitle is "Holes", pageCount is 233 (copies of the arguments)
4 19 title becomes "Holes"
5 20 pages becomes 233
6 21 checkedOut becomes false; every instance variable now has a value
7 22 Prints the new state
8 6 The constructor ends; the reference to the new object is stored in novel
9 7 Prints After the call
Before the call
Holes, 233 pages, checked out: false
After the call

Notice line 21. No parameter supplies checkedOut; the constructor simply decides that every new book starts on the shelf. A starting value can come from a parameter or be fixed by the constructor.

Now vary the parameter list: a constructor does not need parameters at all. Every new scoreboard starts the same way, at 0 to 0 in period 1, so its constructor takes nothing and sets fixed values. This program also builds two objects.

ScoreboardStart.java
public class ScoreboardStart
{
    public static void main(String[] args)
    {
        Scoreboard gym = new Scoreboard();
        Scoreboard field = new Scoreboard();
        System.out.println(gym == field);
    }
}

class Scoreboard
{
    private int homeScore;
    private int awayScore;
    private int period;

    public Scoreboard()
    {
        homeScore = 0;
        awayScore = 0;
        period = 1;
        System.out.println("Home " + homeScore + ", Away " + awayScore + ", Period " + period);
    }
}
Home 0, Away 0, Period 1
Home 0, Away 0, Period 1
false

Each new on lines 5 and 6 sets aside memory for a separate Scoreboard, runs the constructor for it, and returns a different reference. The two objects happen to have identical states, but they are two objects. Line 7 compares the references with == (Topic 2.6), and false confirms they are not aliases: changing the gym’s score later would never change the field’s.

Watch out

Giving a constructor a return type. Because methods have a return type, students sometimes write void in front of a constructor’s name:

BookVoid.java
public class BookVoid
{
    public static void main(String[] args)
    {
        Book novel = new Book("Holes", 233);
    }
}

class Book
{
    private String title;
    private int pages;

    public void Book(String bookTitle, int pageCount)
    {
        title = bookTitle;
        pages = pageCount;
    }
}

With void, line 13 is no longer a constructor; it is a method that happens to be named Book. The class now has no constructor taking a String and an int, so line 5 fails:

BookVoid.java:5: error: constructor Book in class Book cannot be applied to given types;
  required: no arguments
  found:    String,int

(The exact wording can vary between Java versions.) The error points at the call, but the mistake is in the header. The fix is to delete void: public Book(String bookTitle, int pageCount). Section 3.4.4 explains where the “no arguments” constructor in the message comes from.

Pause and try

Question 3 · Multiple choice

Which is a correct constructor header for a class named Movie?

  1. public void Movie(String movieTitle)
  2. public Movie movie(String movieTitle)
  3. public Movie(String movieTitle)
  4. public movie(String movieTitle)
Check your reasoning

C. A constructor is public, has exactly the class name, and has no return type.

  • A is wrong: void is a return type, so this declares a method named Movie, not a constructor.
  • B is wrong: Movie here is a return type in front of a method named movie, so it is a method too.
  • D is wrong: the name must match the class name exactly, including the capital M.

Reread 3.4.2 Writing a Constructor if you chose differently.

Question 4 · Tracing

What does this program print?

StudentTrace.java
public class StudentTrace
{
    public static void main(String[] args)
    {
        System.out.println("Start");
        Student first = new Student("Mia", 11);
        Student second = new Student("Leo", 9);
        System.out.println("End");
    }
}

class Student
{
    private String name;
    private int grade;

    public Student(String studentName, int gradeLevel)
    {
        name = studentName;
        grade = gradeLevel;
        System.out.println(name + " is in grade " + grade);
    }
}
Check your reasoning
Start
Mia is in grade 11
Leo is in grade 9
End
Order Line(s) What happens
1 5 Prints Start
2 6, 17–21 First object: name is "Mia", grade is 11; prints its state
3 6 Reference to the first object stored in first
4 7, 17–21 Second object, separate memory: name is "Leo", grade is 9; prints it
5 7 Reference to the second object stored in second
6 8 Prints End

Each new runs the constructor completely before main continues, and each object gets its own instance variables, so setting Leo’s values does not change Mia’s.

Reread 3.4.2 Writing a Constructor if your output differed.

Section 3 of 5

3.4.3 Parameters Supply the Starting Values

A constructor with no parameters builds identical objects, which is right for a scoreboard but wrong for pets: every pet has a different name and age. How does the code that writes new Pet(...) tell the constructor which pet to build?

Through parameters, exactly as in Topic 1.13: the caller passes arguments, and each parameter starts with a copy of its argument. The constructor’s job is to move that data into the instance variables. A parameter is a temporary variable that disappears when the constructor ends; an instance variable lasts as long as the object. If the constructor does not copy a parameter’s value into an instance variable, the value is lost.

There is a naming rule to follow for now: give each parameter a different name from the instance variable it fills, such as petName for name. You will see why in the Watch Out below.

Key idea

Constructor parameters carry the data for the new object’s starting state. The body must assign each one to its instance variable, because parameters vanish when the constructor ends.

Worked example: Two pets from one constructor

Pet has three instance variables. Two get their values from parameters; the third, vetVisits, always starts at 0 for a new pet.

PetCreation.java
public class PetCreation
{
    public static void main(String[] args)
    {
        Pet dog = new Pet("Biscuit", 3);
        Pet cat = new Pet("Pepper", 7);
    }
}

class Pet
{
    private String name;
    private int age;
    private int vetVisits;

    public Pet(String petName, int petAge)
    {
        name = petName;
        age = petAge;
        vetVisits = 0;
        System.out.println(name + ", age " + age + ", vet visits: " + vetVisits);
    }
}
Call petName petAge name set to age set to vetVisits set to
Line 5 "Biscuit" 3 "Biscuit" 3 0
Line 6 "Pepper" 7 "Pepper" 7 0
Biscuit, age 3, vet visits: 0
Pepper, age 7, vet visits: 0

Same constructor, different arguments, different starting states. Every instance variable got a value in both objects, two from parameters and one fixed.

Now vary what the body does with a parameter. The body is ordinary code, so it can compute a starting value from the parameters, including with a Boolean expression (Topic 2.2) and an if statement (Topic 2.3). A concert ticket in rows 1 through 3 is a VIP ticket costing $80; any other row costs $45.

ConcertTicketPrice.java
public class ConcertTicketPrice
{
    public static void main(String[] args)
    {
        ConcertTicket front = new ConcertTicket("The Comets", 2);
        ConcertTicket back = new ConcertTicket("The Comets", 15);
    }
}

class ConcertTicket
{
    private String band;
    private int row;
    private boolean vip;
    private double price;

    public ConcertTicket(String bandName, int seatRow)
    {
        band = bandName;
        row = seatRow;
        vip = seatRow <= 3;
        if (vip)
        {
            price = 80.0;
        }
        else
        {
            price = 45.0;
        }
        System.out.println(band + " row " + row + ": VIP " + vip + ", $" + price);
    }
}

For the first ticket, seatRow is 2, so line 21 sets vip to 2 <= 3, which is true, and the if sets price to 80.0. For the second, seatRow is 15, vip is false, and the else sets price to 45.0.

The Comets row 2: VIP true, $80.0
The Comets row 15: VIP false, $45.0

The caller passed only a band and a row, yet all four instance variables got starting values: two copied from parameters and two computed from them.

Watch out

Naming a parameter the same as its instance variable. It seems natural to call the parameter name because it fills name:

PetSameName.java
public class PetSameName
{
    public static void main(String[] args)
    {
        Pet dog = new Pet("Biscuit", 3);
        System.out.println("A Pet was created.");
    }
}

class Pet
{
    private String name;
    private int age;

    public Pet(String name, int age)
    {
        name = name;
        age = age;
    }
}

This compiles and runs, printing A Pet was created., but the pet never gets its name or age. Inside the constructor, the name name now means the parameter, because the closer declaration wins. So line 17 copies the parameter into itself and the instance variable is never touched:

Variable After lines 17 and 18
parameter name "Biscuit" (copied into itself)
parameter age 3 (copied into itself)
instance variable name still null: never assigned
instance variable age still 0: never assigned

(Where null and 0 come from is section 3.4.4.) The fix is to rename the parameters, public Pet(String petName, int petAge), and assign name = petName; and age = petAge;. Topic 3.9 shows a keyword that lets a parameter share the instance variable’s name; until then, use different names.

Pause and try

Question 5 · Tracing

What does this program print?

GymPassTrace.java
public class GymPassTrace
{
    public static void main(String[] args)
    {
        GymPass first = new GymPass("Ines", 3, 17);
        GymPass second = new GymPass("Omar", 2, 25);
    }
}

class GymPass
{
    private String member;
    private int months;
    private boolean student;
    private double cost;

    public GymPass(String memberName, int monthCount, int age)
    {
        member = memberName;
        months = monthCount;
        student = age < 19;
        cost = monthCount * 30.0;
        if (student)
        {
            cost = cost / 2;
        }
        System.out.println(member + ": " + months + " months, $" + cost + ", student " + student);
    }
}
Check your reasoning
Ines: 3 months, $45.0, student true
Omar: 2 months, $60.0, student false
Line First call ("Ines", 3, 17) Second call ("Omar", 2, 25)
19 member is "Ines" member is "Omar"
20 months is 3 months is 2
21 17 < 19: student is true 25 < 19: student is false
22 cost is 3 * 30.0 = 90.0 cost is 2 * 30.0 = 60.0
23–26 student is true: cost becomes 45.0 skipped

age is a parameter only; no instance variable stores it. It is used to compute student and then disappears when the constructor ends.

Reread 3.4.3 Parameters Supply the Starting Values if your output differed.

Question 6 · Multiple choice

A class has the instance variable private int speed;. Which constructor stores the caller’s value in speed?

  1. public Fan(int speed) { speed = speed; }
  2. public Fan(int startSpeed) { startSpeed = speed; }
  3. public Fan(int startSpeed) { speed = startSpeed; }
  4. public Fan(int startSpeed) { int speed = startSpeed; }
Check your reasoning

C. The parameter has a different name, and the assignment puts the parameter’s value into the instance variable (the variable being changed goes on the left of =).

  • A is wrong: inside the constructor speed means the parameter, so this copies the parameter into itself and the instance variable is never assigned.
  • B is wrong: the assignment runs backward. It overwrites the parameter with the instance variable’s value, and speed is never set.
  • D is wrong: int speed declares a brand-new local variable that disappears when the constructor ends; the instance variable is never set.

Reread 3.4.3 Parameters Supply the Starting Values if you chose differently.

Section 4 of 5

3.4.4 Default Values and the Default Constructor

The Watch Out above said an instance variable that was never assigned is “still null” or “still 0.” But nobody wrote null or 0 anywhere. Where do those values come from? And what happens if a class has no constructor at all?

Remember step 1 of a constructor call from 3.4.2: memory is set aside for the new object. Java never leaves that memory holding leftover junk. Before any constructor code runs, every instance variable is given a default value that depends only on its type:

Type of the instance variable Default value
int 0
double 0.0
boolean false
any reference type (String, Scanner, Book, …) null

Each is the “nothing yet” value for its type: zero for numbers, false for a true/false fact, and null, meaning “no object” (Topic 1.13), for references. Your constructor’s assignments then replace these defaults. Any instance variable the constructor skips keeps its default.

Worked example: A constructor that forgets four variables

This constructor sets only name, then prints all five instance variables.

PlayerForgot.java
public class PlayerForgot
{
    public static void main(String[] args)
    {
        Player rookie = new Player("Jordan");
    }
}

class Player
{
    private String name;
    private String team;
    private int goals;
    private double average;
    private boolean injured;

    public Player(String playerName)
    {
        name = playerName;
        System.out.println("name: " + name);
        System.out.println("team: " + team);
        System.out.println("goals: " + goals);
        System.out.println("average: " + average);
        System.out.println("injured: " + injured);
    }
}
name: Jordan
team: null
goals: 0
average: 0.0
injured: false

Line 19 replaced name’s default. The other four were never assigned, so each still holds the default for its type: String gives null, int gives 0, double gives 0.0, and boolean gives false. This program runs without an error, which is exactly the danger: team being null may cause trouble much later, far from this constructor. That is why a constructor should set every instance variable on purpose, even when the value it wants happens to match the default.

Now vary the class: remove the constructor entirely.

DefaultLamp.java
public class DefaultLamp
{
    public static void main(String[] args)
    {
        Lamp desk = new Lamp();
        System.out.println("A Lamp was created.");
    }
}

class Lamp
{
    private String color;
    private int brightness;
    private double watts;
    private boolean on;
}
A Lamp was created.

Lamp has no constructor, yet line 5 calls new Lamp() and it works. When a class has no constructor written at all, Java supplies one: a constructor with no parameters and an empty body. It is called the default constructor. Since its body does nothing, the new lamp’s instance variables keep their defaults: color is null, brightness is 0, watts is 0.0, and on is false.

Key idea

Instance variables start with default values: 0 for int, 0.0 for double, false for boolean, and null for reference types. If a class has no constructor written, Java provides a no-parameter default constructor that leaves every instance variable at its default.

Watch out

Expecting the default constructor after you write your own. Java supplies the default constructor only when the class has no constructor. As soon as you write any constructor, Java stops supplying it:

NoDefaultAnymore.java
public class NoDefaultAnymore
{
    public static void main(String[] args)
    {
        Lamp desk = new Lamp();
    }
}

class Lamp
{
    private String color;
    private int brightness;

    public Lamp(String lampColor, int level)
    {
        color = lampColor;
        brightness = level;
    }
}
NoDefaultAnymore.java:5: error: constructor Lamp in class Lamp cannot be applied to given types;
  required: String,int
  found:    no arguments
  reason: actual and formal argument lists differ in length

The only constructor needs a String and an int, and the call passes nothing. Fix it by passing the arguments the constructor needs, such as new Lamp("white", 60), or, if the class should also allow new Lamp(), by writing a no-parameter constructor too (two constructors with different signatures are overloaded, Topic 1.13). This also explains the BookVoid error in 3.4.2: with the “constructor” turned into a method, Book had no constructor, so Java supplied the default one, which takes no arguments.

Pause and try

Question 7 · Tracing

What does this program print?

SensorDefaults.java
public class SensorDefaults
{
    public static void main(String[] args)
    {
        Sensor porch = new Sensor("porch", 21.5);
    }
}

class Sensor
{
    private String location;
    private double temperature;
    private int readings;
    private boolean alarm;
    private String unit;

    public Sensor(String place, double startTemp)
    {
        location = place;
        readings = readings + 1;
        System.out.println(location + " " + temperature + " " + readings);
        System.out.println(alarm + " " + unit);
    }
}
Check your reasoning
porch 0.0 1
false null
Instance variable Default After the constructor body
location null "porch" (line 19)
temperature 0.0 still 0.0: startTemp is never stored
readings 0 0 + 1 = 1 (line 20 starts from the default)
alarm false still false
unit null still null

The trap is temperature: the caller passed 21.5, but the constructor never assigns startTemp to anything, so the value is lost when the constructor ends.

Reread 3.4.4 Default Values and the Default Constructor if your output differed.

Question 8 · Debugging

This program should print Holes has 233 pages, but it prints Holes has 0 pages. Find the error, explain why 0 appears, and write the corrected line.

BookReversed.java
public class BookReversed
{
    public static void main(String[] args)
    {
        Book story = new Book("Holes", 233);
    }
}

class Book
{
    private String title;
    private int pages;

    public Book(String bookTitle, int pageCount)
    {
        title = bookTitle;
        pageCount = pages;
        System.out.println(title + " has " + pages + " pages");
    }
}
Check your reasoning

Corrected line 17:

pages = pageCount;

Line 17 has the assignment backward. = stores the right side into the variable on the left, so pageCount = pages; overwrites the parameter with the instance variable’s value and never changes pages. pages therefore keeps its default, 0 for an int, and line 18 prints Holes has 0 pages. There is no compile error because both sides are int variables. With the fix, the program prints Holes has 233 pages.

Reread 3.4.3 Parameters Supply the Starting Values and 3.4.4 Default Values and the Default Constructor if you missed it.

Section 5 of 5

3.4.5 Mutable Objects as Parameters

So far every parameter has been a primitive or a String. What if a constructor receives an object that can change? Call by value copies the argument, but for a reference type the argument is a reference, so the constructor gets a copy of the address, not a copy of the object.

An object whose state can change after it is built is called mutable. You already know one. In Topic 2.6 you saw that a Scanner moves forward through its input each time you read from it, so reading changes its state. A String is not mutable: once built, its characters never change (Topic 1.15). Storing a reference to a String is always safe, because nobody can change the object behind your back.

Worked example: A grader that shares the caller's Scanner

The Grader constructor stores the Scanner it receives and reads the first answer from it.

GraderShared.java
import java.util.Scanner;

public class GraderShared
{
    public static void main(String[] args)
    {
        Scanner key = new Scanner("B D A C");
        Grader quizOne = new Grader(key);
        System.out.println("main reads: " + key.next());
    }
}

class Grader
{
    private Scanner answers;
    private String firstAnswer;

    public Grader(Scanner answerKey)
    {
        answers = answerKey;
        firstAnswer = answers.next();
        System.out.println("Grader reads: " + firstAnswer);
    }
}
Grader reads: B
main reads: D

Line 20 stores the parameter’s reference in the instance variable, so answers (inside the object) and key (in main) are aliases of one Scanner. Line 21 reads B through answers, and that moves the shared Scanner forward. When main reads through key on line 9, it gets D, not B. Building a Grader quietly changed an object that belongs to main. The reverse is also true: anything main later does with key changes what the grader will read next.

This is why, when a constructor receives a mutable object, the instance variable should hold a copy of that object: a new object with the same values. Then the instance variable does not refer to the caller’s object, so code in the class cannot change the caller’s object, and changes the caller makes cannot reach inside the new object.

A Scanner cannot be copied, but a class can offer a way to copy its own objects. Below, Address is mutable: its moveTo method changes the street. (Lines 27–30 are a method; you will learn to write methods in Topic 3.5. You only need to know that calling moveTo changes an Address object’s street.) Address also has a second constructor, on lines 21–25, that builds a new Address holding the same street and city as one it is given. It can read original.street because private limits access to code written inside the Address class (Topic 3.3), and this constructor is inside it.

OrderCopy.java
public class OrderCopy
{
    public static void main(String[] args)
    {
        Address home = new Address("12 Oak St", "Akron");
        Order lamp = new Order("lamp", home);
    }
}

class Address
{
    private String street;
    private String city;

    public Address(String streetName, String cityName)
    {
        street = streetName;
        city = cityName;
    }

    public Address(Address original)
    {
        street = original.street;
        city = original.city;
    }

    public void moveTo(String newStreet)
    {
        street = newStreet;
    }
}

class Order
{
    private String item;
    private Address shipTo;

    public Order(String itemName, Address destination)
    {
        item = itemName;
        shipTo = new Address(destination);
        System.out.println("Same Address object as the caller's? " + (shipTo == destination));
    }
}
Same Address object as the caller's? false

Line 41 calls new Address(destination), so shipTo gets a reference to a new object with the same values. Line 42 compares references with == and confirms that shipTo and the caller’s home are different objects. If the order had instead stored the reference directly, shipTo = destination;, the same program prints Same Address object as the caller's? true:

Line 41 is What shipTo refers to If main later calls home.moveTo("9 Elm St")
shipTo = destination; the caller’s own object the order’s address changes too
shipTo = new Address(destination); a new copy the order still ships to 12 Oak St

Key idea

When a constructor receives a mutable object, initialize the instance variable with a copy of that object, not the reference itself. Otherwise the object and the caller share one object, and a change through either one shows up in both.

Watch out

Thinking call by value already protects objects. Call by value copies the argument, and for a reference type the argument is a reference. shipTo = destination; copies an address onto a second sticky note; it does not build a second house. Only new builds a new object, so making a real copy always involves new.

Pause and try

Question 9 · Multiple choice

A class Team has the instance variable private Roster players;, where Roster is a mutable class with a constructor Roster(Roster original) that makes a copy. Which line in Team’s constructor follows the guideline for a parameter Roster startPlayers?

  1. players = startPlayers;
  2. startPlayers = players;
  3. players = new Roster(startPlayers);
  4. Roster players = startPlayers;
Check your reasoning

C. For a mutable parameter, the instance variable should refer to a copy, and new Roster(startPlayers) builds a new Roster with the same values.

  • A is wrong: it stores the caller’s reference, so the team and the caller share one Roster; a change through either shows up in both.
  • B is wrong: it runs backward and changes only the parameter; players keeps its default, null.
  • D is wrong: it declares a new local variable named players that disappears when the constructor ends, and it would share the caller’s object anyway.

Reread 3.4.5 Mutable Objects as Parameters if you chose differently.

Question 10 · Short answer

In GraderShared.java, a classmate says, “main passed key by value, so the Grader got its own copy and reading from it cannot affect main.” Explain what is wrong with this reasoning.

Check your reasoning

Model answer: Call by value copies the argument, but key holds a reference, so the constructor received a copy of the reference, not a copy of the Scanner. Line 20 stores that reference, making answers and key aliases of one Scanner object. A Scanner is mutable, so when the grader reads B, the shared object moves forward and main reads D next.

A complete answer must:

  • say the copy is of the reference (address), not of the object, and
  • explain that both variables then refer to one mutable object, so a change through one is seen through the other.

Reread 3.4.5 Mutable Objects as Parameters if your reasoning differed.

Wrap-up · 1 of 5

Putting it together

A hotel program records each stay. A stay has a guest, a number of nights, a total cost, a paid status, and a billing address. Guests booking just one night can leave out the number of nights. Read the whole file, then follow the trace.

Booking.java
public class Booking
{
    public static void main(String[] args)
    {
        Address ana = new Address("12 Oak St", "Akron");
        System.out.println("Booking rooms...");
        HotelStay longStay = new HotelStay("Ana", 3, ana);
        HotelStay quickStay = new HotelStay("Ana", ana);
        System.out.println("Done");
    }
}

class Address
{
    private String street;
    private String city;

    public Address(String streetName, String cityName)
    {
        street = streetName;
        city = cityName;
    }

    public Address(Address original)
    {
        street = original.street;
        city = original.city;
    }

    public void moveTo(String newStreet)
    {
        street = newStreet;
    }
}

class HotelStay
{
    private String guest;
    private int nights;
    private double total;
    private boolean paid;
    private Address billing;

    public HotelStay(String guestName, int stayNights, Address guestAddress)
    {
        guest = guestName;
        nights = stayNights;
        total = stayNights * 89.5;
        paid = false;
        billing = new Address(guestAddress);
        System.out.println(guest + ": " + nights + " nights, $" + total + ", paid " + paid);
    }

    public HotelStay(String guestName, Address guestAddress)
    {
        guest = guestName;
        nights = 1;
        total = 89.5;
        paid = false;
        billing = new Address(guestAddress);
        System.out.println(guest + ": " + nights + " night, $" + total + ", paid " + paid);
    }
}
Order Line(s) What happens Printed
1 5 An Address is built for 12 Oak St, Akron; ana refers to it
2 6 Prints Booking rooms...
3 7 Three arguments match HotelStay(String, int, Address); memory is set aside with defaults
4 46–49 guest is "Ana", nights is 3, total is 3 * 89.5 = 268.5, paid is false
5 50 new Address(guestAddress) builds a copy, so billing does not share main’s Address
6 51 Prints the state; the reference is stored in longStay Ana: 3 nights, $268.5, paid false
7 8 Two arguments match HotelStay(String, Address), the overloaded constructor
8 56–60 nights is fixed at 1, total at 89.5, paid at false; billing is another copy
9 61 Prints the state; the reference is stored in quickStay Ana: 1 night, $89.5, paid false
10 9 Prints Done
Booking rooms...
Ana: 3 nights, $268.5, paid false
Ana: 1 night, $89.5, paid false
Done

Check the habits from this chapter against the code. Both constructors set all five instance variables, including paid = false, which matches the default but is written on purpose. Every parameter name differs from its instance variable. And because Address is mutable, each stay keeps its own copy: if Ana later moves and main calls ana.moveTo(...), the addresses on the existing stays do not change. Five objects exist at the end, one for each new that ran (lines 5, 7, 50, 8, and 60): ana’s Address, two HotelStay objects, and two Address copies.

Wrap-up · 2 of 5

Vocabulary

Term Definition Example
attribute A fact an object keeps track of a book’s title
instance variable A variable declared in a class, outside constructors and methods, that each object has its own copy of private int pages;
state The values of an object’s instance variables at a given moment "Holes", 233, false
has-a relationship The connection between an object and its instance variables a book has a title
constructor Code with the class name and no return type that sets a new object’s initial state public Book(String bookTitle, int pageCount)
initial state The values an object’s instance variables hold when it is created a new scoreboard at 0 to 0
default value The value an instance variable has before any code assigns it, based on its type 0, 0.0, false, null
default constructor The no-parameter constructor Java supplies when a class has no constructor written new Lamp() with no constructor in Lamp
mutable Describes an object whose state can change after it is built a Scanner; not a String
Wrap-up · 3 of 5

Chapter summary

  • An object’s state is the values of its instance variables at a given moment. The instance variables belong to the object, giving a has-a relationship, and each object has its own copy.
  • A constructor has the class name, is public, and has no return type. Calling it with new sets aside memory for the object, runs the body, and returns a reference to the new object.
  • A constructor should give every instance variable a starting value. Values can come from parameters (named differently from the instance variables), be fixed, or be computed from parameters.
  • Instance variables start at their default values (0, 0.0, false, null). If a class has no constructor, Java supplies a no-parameter default constructor that leaves them that way; writing any constructor removes it.
  • When a constructor receives a mutable object, the instance variable should hold a copy made with new, so the object and the caller never share it.
Wrap-up · 4 of 5

Review questions

Question 11 · Multiple choice

Book has the constructor from 3.4.2. Which list gives, in order, what happens when Book novel = new Book("Holes", 233); runs?

  1. The body runs → memory is set aside → the reference is stored in novel
  2. Memory is set aside → the body runs → the reference is stored in novel
  3. The reference is stored in novel → memory is set aside → the body runs
  4. Memory is set aside → the reference is stored in novel → the body runs
Check your reasoning

B. new first sets aside memory for the object (instance variables at their defaults), then the constructor body runs to set the initial state, and only when it finishes is the reference returned and stored by =.

  • A is wrong: the body assigns to the object’s instance variables, so the object’s memory must exist before the body can run.
  • C is wrong: there is no reference to store until the object exists, and = stores the result of the whole new expression, which is ready only after the constructor finishes.
  • D is wrong: the reference is stored only after the constructor finishes; Topic 1.13’s flow of control shows the call completes before the statement does.

Reread 3.4.2 Writing a Constructor if you chose differently.

Question 12 · Short answer

A bike-share program needs a Bike class. Each bike has an ID number, a battery level from 0.0 to 100.0, and whether it is currently rented. Name a type for each instance variable, explain the has-a relationship, and describe what a reasonable constructor that takes only the ID would set the initial state to.

Check your reasoning

Model answer: int id, double battery, and boolean rented. A bike has an ID, has a battery level, and has a rented status, so these are instance variables each Bike object owns. A constructor with one int parameter (for example bikeId) would set id from the parameter and give the others fixed starting values, such as battery = 100.0; and rented = false; for a new, charged bike that is not yet rented. It should set all three on purpose rather than rely on defaults; a default battery of 0.0 would mean a dead bike.

A complete answer must:

  • give sensible types (int, double, boolean),
  • describe the has-a relationship, and
  • say the constructor sets every instance variable, one from the parameter and the rest to chosen starting values.

Reread 3.4.1 Object State and Instance Variables and 3.4.3 Parameters Supply the Starting Values if your answer differed.

Question 13 · Tracing

What does this program print?

CampSignup.java
public class CampSignup
{
    public static void main(String[] args)
    {
        Camper first = new Camper("Rosa", 12);
        Camper second = new Camper("Eli", 8);
        Camper third = new Camper("Kai");
    }
}

class Camper
{
    private String name;
    private int age;
    private boolean swimmer;
    private double fee;

    public Camper(String camperName, int camperAge)
    {
        name = camperName;
        age = camperAge;
        swimmer = camperAge >= 10;
        fee = 150.0;
        System.out.println(name + " " + age + " " + swimmer + " " + fee);
    }

    public Camper(String camperName)
    {
        name = camperName;
        System.out.println(name + " " + age + " " + swimmer + " " + fee);
    }
}
Check your reasoning
Rosa 12 true 150.0
Eli 8 false 150.0
Kai 0 false 0.0
Call Constructor name age swimmer fee
new Camper("Rosa", 12) Camper(String, int) "Rosa" 12 12 >= 10: true 150.0
new Camper("Eli", 8) Camper(String, int) "Eli" 8 8 >= 10: false 150.0
new Camper("Kai") Camper(String) "Kai" 0 false (default) 0.0 (default)

The one-argument constructor sets only name, so the other three keep their defaults. That is legal, but it is why constructors should set every instance variable: Kai’s fee of 0.0 is almost certainly a bug.

Reread 3.4.4 Default Values and the Default Constructor if your third line differed.

Question 14 · Debugging

This program should create locker 214 with a blue lock, but it does not compile. Explain the error and write a corrected line 5.

LockerNoArgs.java
public class LockerNoArgs
{
    public static void main(String[] args)
    {
        Locker gymLocker = new Locker();
    }
}

class Locker
{
    private int number;
    private String lockColor;

    public Locker(int lockerNumber, String color)
    {
        number = lockerNumber;
        lockColor = color;
        System.out.println("Locker " + number + " has a " + lockColor + " lock");
    }
}
Check your reasoning

Corrected line 5:

Locker gymLocker = new Locker(214, "blue");

The compiler reports constructor Locker in class Locker cannot be applied to given types with required: int,String and found: no arguments. Locker has a constructor that needs an int and a String. Because the class has a constructor written, Java does not supply a default constructor, so there is no Locker() to call. Passing the locker number and lock color matches the parameter list in number, order, and type. The fixed program prints Locker 214 has a blue lock.

Reread 3.4.4 Default Values and the Default Constructor if you expected new Locker() to work.

Question 15 · Multiple choice

A class has the instance variables private String city;, private double rainfall;, and private boolean flooded;. Which constructor body correctly sets the whole initial state, given the parameters String cityName and double inches?

  1. city = cityName; rainfall = inches;
  2. cityName = city; inches = rainfall; flooded = false;
  3. city = cityName; rainfall = inches; flooded = inches > 10.0;
  4. String city = cityName; double rainfall = inches; boolean flooded = false;
Check your reasoning

C. Each instance variable is on the left of = and gets a value: two from the parameters and flooded computed from inches.

  • A is wrong: it compiles, but flooded is never set and only has the default false by accident. A constructor should set every instance variable on purpose.
  • B is wrong: the first two assignments run backward, overwriting the parameters, so city stays null and rainfall stays 0.0.
  • D is wrong: each line declares a new local variable that disappears when the constructor ends, so all three instance variables keep their defaults.

Reread 3.4.3 Parameters Supply the Starting Values if you chose differently.

Question 16 · Short answer

The Order constructor in 3.4.5 makes a copy of its Address parameter, but the Book constructor in 3.4.2 stores its String parameter directly with title = bookTitle;. Explain why Book does not need to copy the String.

Check your reasoning

Model answer: The copy rule is for mutable objects. A String is not mutable: once it is built, its characters can never change. title and the caller’s variable do refer to the same String object, but since nobody can change that object, sharing it cannot cause a surprise. An Address can change through moveTo, so sharing it would let a change by the caller show up in the order.

A complete answer must:

  • say String objects cannot change (are not mutable) while Address objects can, and
  • explain that sharing only causes trouble when the shared object can change.

Reread 3.4.5 Mutable Objects as Parameters if your reasoning differed.

Question 17 · Tracing

This program uses the Grader class from 3.4.5. What does it print? Then explain in one sentence why the second grader does not read A.

GraderTwice.java
import java.util.Scanner;

public class GraderTwice
{
    public static void main(String[] args)
    {
        Scanner key = new Scanner("A C B D");
        Grader quizOne = new Grader(key);
        Grader quizTwo = new Grader(key);
        System.out.println("main reads: " + key.next());
    }
}

class Grader
{
    private Scanner answers;
    private String firstAnswer;

    public Grader(Scanner answerKey)
    {
        answers = answerKey;
        firstAnswer = answers.next();
        System.out.println("Grader reads: " + firstAnswer);
    }
}
Check your reasoning
Grader reads: A
Grader reads: C
main reads: B
Step Read through Token read Next token in the shared Scanner
Line 8, first grader answers (alias of key) A C
Line 9, second grader answers (alias of key) C B
Line 10, main key B D

Both graders store the reference they were given, so key, the first grader’s answers, and the second grader’s answers are all aliases of one mutable Scanner. Each read moves that one object forward, so the second grader reads C instead of starting from A.

Reread 3.4.5 Mutable Objects as Parameters if your output differed.

Wrap-up · 5 of 5

Reflection

  • I can describe an object’s state and the has-a relationship between an object and its instance variables. Reread
  • I can write a constructor header with no return type and explain what happens in memory when it is called. Reread
  • I can use parameters with different names to give every instance variable a starting value. Reread
  • I can state the default values for int, double, boolean, and reference types, and say when Java supplies a default constructor. Reread
  • I can explain why a constructor should copy a mutable object it receives. Reread