1.13.1 Constructors and the new Keyword
A class is only a blueprint. A blueprint for a house is not a house you can live in; someone has to build the house from it. In the same way, before your program can use a String holding your name or a Scanner reading the keyboard, an actual object has to be built from the class. How does a program ask Java to build one?
Every class comes with special blocks of code whose only job is to build objects of that class. Think of them as the construction crew that comes with the blueprint. You ask for a new object, the crew builds it, and you get back the object’s address.
That construction code is called a constructor: a block of code in a class that runs to create a new object of that class. Two facts make constructors easy to spot:
- A constructor has the same name as its class, capital letter and all. The
Stringclass has constructors namedString; theScannerclass has constructors namedScanner. - You call a constructor by writing the keyword
newin front of it.newtells Java “build a brand-new object,” and the constructor call after it says which class to build and with what information.
Creating an object this way is called instantiation, because the result is a new instance of the class (the word “instance” from Topic 1.12).
String greeting = new String("Good morning");
| Piece | What it is |
|---|---|
String greeting |
Declares a variable named greeting that can hold a reference to a String |
= |
Stores the result of the right side in the variable (Topic 1.4) |
new |
Asks Java to build a new object |
String(...) |
The constructor call: same name as the class, followed by parentheses |
"Good morning" |
The information passed to the constructor: the characters the new object holds |
Key idea
An object is created by writing new followed by a call to one of the class’s constructors. A constructor always has
the same name as its class.
Worked example: Building a String object
Read the two statements and think about what exists in memory after each.
String greeting = new String("Good morning");
System.out.println(greeting);- Java evaluates the right side of line 1 first.
newasks for a new object, and the callString("Good morning")runs theStringconstructor, which builds aStringobject holding the charactersGood morning. - The result of
newis a reference to that new object (its address). The=stores that reference ingreeting. - Line 2 prints the object that
greetingrefers to.
Good morningNow change the class. You have used this line since Topic 1.4, perhaps without knowing what each word meant:
import java.util.Scanner;
public class KeyboardScanner
{
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
System.out.println("A Scanner object is ready.");
}
}Line 7 follows exactly the same pattern. Scanner keyboard declares a variable that can refer to a Scanner. new Scanner(System.in) calls the Scanner constructor, passing it System.in, which stands for the keyboard. The constructor builds a Scanner object connected to the keyboard, and its reference is stored in keyboard. The program then prints its message:
A Scanner object is ready.
Nothing was typed, and nothing needed to be: creating the Scanner only sets it up to read. Reading happens later, when you ask it for input. The class changed (String to Scanner) and so did the information passed in, but the shape Type name = new Type(...); stayed the same.
(You have probably also written String name = "Ada"; without new. A string literal is a shortcut that String alone gets; Topic 1.15 covers it. For every other class, objects come from new.)
Watch out
Leaving out new. Because a constructor call looks like a method call from Topic 1.9, students sometimes write it without new:
String greeting = String("Good morning");
System.out.println(greeting);Java reports cannot find symbol and names the missing symbol as method String(String). Without new, Java thinks you are calling an ordinary method named String, and there is no such method. The fix is String greeting = new String("Good morning");. The word new is what tells Java this is a request to build an object.
Pause and try
Question 1 · Multiple choice
Which statement creates a new String object holding Hello by calling a constructor?
String word = String("Hello");String word = new String("Hello");new String word = "Hello";String word = new("Hello");
Check your reasoning
B. An object is created with new followed by a constructor call, and the constructor has the same name as the class: new String("Hello").
- A is wrong: without
new, Java looks for a method namedString, finds none, and reportscannot find symbol. - C is wrong:
newgoes in front of the constructor call on the right side of=, not in the variable declaration. - D is wrong:
newmust be followed by the constructor’s name, which is the class name.new("Hello")does not say which class to build.
Reread 1.13.1 Constructors and the new Keyword if you chose differently.
Question 2 · Debugging
This program is supposed to create a Scanner that reads from the keyboard, but it does not compile. Find the error and write the corrected line.
import java.util.Scanner;
public class ScannerNoNew
{
public static void main(String[] args)
{
Scanner input = Scanner(System.in);
System.out.println("Ready");
}
}Check your reasoning
Corrected line 7:
Scanner input = new Scanner(System.in);Line 7 is missing new. The compiler reports cannot find symbol with symbol: method Scanner(InputStream): it treated Scanner(System.in) as a call to a method named Scanner, and no such method exists. A constructor is only called to build an object when new comes before it. With the fix, the program prints Ready.
Reread 1.13.1 Constructors and the new Keyword if you missed it.
1.13.2 Reference Variables and null
Building an object is only half the job. If the reference that new hands back is not stored anywhere, your program has no way to find the object again. So where does it go, and what type must that variable be?
Recall from Topic 1.12 that a variable of a reference type holds a reference, which you can think of as the memory address of an object, not the object itself. Picture the object as a house and the variable as a sticky note with the house’s address written on it.
The variable’s type must match the kind of object it will refer to. A String variable holds references to String objects; a Scanner variable holds references to Scanner objects. The type is the class name, so declaring the variable looks just like Topic 1.2, with a class name where a primitive type would go: Scanner keyboard;, String city;.
There is one more thing a reference variable can hold. Sometimes there is no object yet, or no object at all. For that, Java has the literal null (from Topic 1.4), a special value meaning “this variable does not refer to any object.” On the sticky-note picture, null is a note with no address on it. Where the picture stops working: a real sticky note can be blank because someone forgot; null is a deliberate value you can assign and print.
Key idea
A variable of a reference type holds either a reference to an object of its type or null when there is no object.
Worked example: Two variables, one object
Here one object is created, and then its reference is copied into a second variable. Watch how many objects exist.
String city = new String("Denver");
String sameCity = city;
System.out.println(city);
System.out.println(sameCity);Line 1 builds one String object and stores its reference in city. Line 2 has no new, so it builds nothing; = copies the reference already stored in city into sameCity. If we call the object’s address “address A,” memory after line 2 looks like this:
| Variable | Holds | Object at that address |
|---|---|---|
city |
reference to address A | String “Denver” |
sameCity |
reference to address A | (the same object) |
Both variables lead to the same object, so both lines print the same text:
Denver
DenverTwo variables, but only one object, because new ran only once. Count the news to count the objects.
Now vary the starting value. This time the variable starts with no object at all:
String nickname = null;
System.out.println(nickname);
nickname = new String("Sky");
System.out.println(nickname);| After line | nickname holds |
Printed |
|---|---|---|
| 1 | null |
|
| 2 | null |
null |
| 3 | reference to “Sky” | |
| 4 | reference to “Sky” | Sky |
When println is given a variable holding null, it prints the word null. Line 3 then creates an object and stores its reference, replacing null just as any assignment replaces an old value.
Watch out
Choosing the wrong variable type. A variable can only hold references to its own type. Storing a Scanner in a String variable does not compile:
import java.util.Scanner;
public class WrongVariableType
{
public static void main(String[] args)
{
String keyboard = new Scanner(System.in);
System.out.println("Ready");
}
}Java reports incompatible types: Scanner cannot be converted to String. The fix is to declare the variable with the class that comes after new: Scanner keyboard = new Scanner(System.in);.
Putting null in a primitive variable. null means “no object,” so it only makes sense for reference types:
int count = null;
System.out.println(count);Java reports incompatible types: <null> cannot be converted to int. An int variable always holds a number, never a reference, so it cannot hold null.
Pause and try
Question 3 · Multiple choice
Which declaration does not compile?
String title = null;Scanner input = new Scanner(System.in);double price = null;String title = new String("Up");
Check your reasoning
C. null means “no object,” so only a reference-type variable can hold it. double is a primitive type, so Java reports that <null> cannot be converted to double.
- A compiles:
Stringis a reference type, so its variable may holdnull. - B compiles: the variable type
Scannermatches the class being built. - D compiles: the variable type
Stringmatches the class being built.
Reread 1.13.2 Reference Variables and null if you chose differently.
Question 4 · Tracing
What does this code print? How many String objects does it create?
String captain = null;
String backup = new String("Rosa");
System.out.println(captain);
captain = backup;
System.out.println(captain);
System.out.println(backup);Check your reasoning
null
Rosa
Rosa| After line | captain |
backup |
Printed |
|---|---|---|---|
| 1 | null |
(not declared yet) | |
| 2 | null |
reference to “Rosa” | |
| 3 | null |
reference to “Rosa” | null |
| 4 | reference to “Rosa” | reference to “Rosa” | |
| 5 | reference to “Rosa” | reference to “Rosa” | Rosa |
| 6 | reference to “Rosa” | reference to “Rosa” | Rosa |
It creates one String object, because new appears once. Line 4 copies the reference from backup into captain; it does not build a second object.
Reread 1.13.2 Reference Variables and null if your trace differed.
1.13.3 Reading a Constructor Signature
So far you have been given the right constructor call. When you meet a new class, though, how do you find out what to put in the parentheses? The same way you found out how to call a method in Topic 1.9: by reading its header in the documentation.
Here are two real constructor headers from the Java documentation, one for each class you know:
String(String original)
Scanner(InputStream source)
A constructor header looks a lot like a method header, with two differences. Its name is the class name. And there is no return type in front of it, not even void, because a constructor’s job is fixed: it builds an object of its own class.
The part in parentheses is the parameter list. For each value the constructor needs, it lists the value’s type and a parameter name: String original means “give me a String; inside the constructor it will be called original.” InputStream source means “give me an InputStream” (the type of System.in, the keyboard).
From the header you can read off the constructor’s signature: the constructor’s name followed by the ordered list of parameter types. The parameter names are left out of the signature.
| Header | Signature |
|---|---|
String(String original) |
String(String) |
Scanner(InputStream source) |
Scanner(InputStream) |
String() |
String() |
The last row is a constructor with an empty parameter list: it needs no information at all. Its signature is just the name with empty parentheses.
Why do the parameter names drop out? Because the caller never uses them. When you write new String("Hi"), all Java has to check is that you passed one String. Whether the constructor calls it original or text inside makes no difference from outside.
Key idea
A constructor signature is the constructor’s name (the same as the class name) plus the ordered list of parameter types. The header also lists parameter names, but the names are not part of the signature.
Worked example: Reading a made-up class's constructor
String and Scanner hide their constructor code. To see inside a constructor, this chapter uses a small class invented for it, Ticket, which stands for a movie ticket. You will write classes and constructors yourself in Unit 3; here you only read them. Its constructor header is:
Ticket(String movie, int seat, double price)Take it apart one piece at a time:
| Piece of the header | Meaning |
|---|---|
Ticket |
Same name as the class, so this is a constructor of Ticket |
String movie |
First value needed: a String, called movie inside |
int seat |
Second value needed: an int, called seat inside |
double price |
Third value needed: a double, called price inside |
Drop the names and keep the types in order: the signature is Ticket(String, int, double). To call it, you need three values, in that order: a String, then an int, then a double.
Order is part of the signature. A constructor with header Ticket(int seat, String movie, double price) would have the signature Ticket(int, String, double), a different signature, even though it uses the same three types.
Watch out
Treating the parameter names as part of the signature. Headers Ticket(String movie, int seat, double price) and Ticket(String title, int row, double cost) look different, but drop the names and both are Ticket(String, int, double): the same signature. A class cannot have two constructors with the same signature, so putting both in one class does not compile:
public class DuplicateSignature
{
public static void main(String[] args)
{
Ticket myTicket = new Ticket("Dune", 14, 12.5);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.println(movie);
}
Ticket(String title, int row, double cost)
{
System.out.println(title);
}
}Java reports constructor Ticket(String,int,double) is already defined in class Ticket. Notice that the compiler’s own description of the constructor is the signature, with no names in it.
Pause and try
Question 5 · Short answer
The Scanner class also has a constructor with the header Scanner(String source). What is its signature? How many arguments does a call to it need, and of what type?
Check your reasoning
Model answer: The signature is Scanner(String). A call needs exactly one argument, and it must be a String.
A complete answer must:
- give the class name followed by the parameter types in parentheses, with the parameter name
sourceleft out, and - say one
Stringargument is needed.
Reread 1.13.3 Reading a Constructor Signature if your answer included source or a return type.
Question 6 · Multiple choice
Which of these is not part of a constructor’s signature?
- The constructor’s name
- The types of its parameters
- The order of its parameters
- The names of its parameters
Check your reasoning
D. A signature is the constructor’s name plus the ordered list of parameter types. Parameter names appear in the header but are not part of the signature, because a caller never uses them.
- A is part of it: the name (which is the class name) starts every signature.
- B is part of it: the types tell the caller what kind of values to pass.
- C is part of it:
Ticket(String, int, double)andTicket(int, String, double)are different signatures.
Reread 1.13.3 Reading a Constructor Signature if you chose differently.
1.13.4 Parameters Set Starting Values
Why do constructors take parameters at all? Because a brand-new object has to start out holding something. A String object holds characters, but which characters? A Scanner reads text, but from where? The object cannot guess; the code that asks for it has to say.
That is the job of constructor parameters. When you call a constructor, the values you pass in become the object’s starting values: the initial values of its attributes (the data each object keeps, from Topic 1.12). Different values passed in mean different objects come out.
Here is what that means for the String(String original) constructor. Its documentation says the new object holds the same characters as the String it was given. So the argument decides the new object’s characters.
Key idea
Parameters let a constructor receive values that set the starting values of the new object’s attributes.
Worked example: Same class, different starting values
Both objects come from the same constructor. Only the value passed in changes.
String first = new String("Ada");
String second = new String("Grace");
System.out.println(first);
System.out.println(second);| Line | Object built | Its starting characters | Reference stored in |
|---|---|---|---|
| 1 | new String |
Ada |
first |
| 2 | new String |
Grace |
second |
Lines 3 and 4 print each object’s characters:
Ada
GraceSame blueprint, same constructor, two different objects, because each call passed a different starting value.
Now vary the class. Scanner has a constructor Scanner(String source) whose parameter sets the text the Scanner will read from, instead of the keyboard. That makes a handy, predictable example, because no one has to type anything:
import java.util.Scanner;
public class ScannerFromText
{
public static void main(String[] args)
{
Scanner reader = new Scanner("85 92");
int firstScore = reader.nextInt();
int secondScore = reader.nextInt();
System.out.println(firstScore);
System.out.println(secondScore);
}
}Line 7 builds a Scanner whose starting text is 85 92. Line 8 calls nextInt, which (as in Topic 1.4) reads the next whole number, so firstScore gets 85; line 9 reads the next one, so secondScore gets 92. (Calling methods on an object, like reader.nextInt(), is taught fully in Topic 1.14.)
85
92
The argument "85 92" decided what this Scanner would read. Pass "60 75" instead, and the same lines would print 60 and 75.
Watch out
Thinking an object with no starting characters is the same as null. The constructor String() takes no arguments and builds a String object with no characters in it. That is still an object; null means there is no object at all.
String empty = new String();
String missing = null;
System.out.print("[");
System.out.print(empty);
System.out.println("]");
System.out.print("[");
System.out.print(missing);
System.out.println("]");[]
[null]The empty object prints nothing between the brackets. The null variable prints the word null, because it refers to no object. Students mix these up because both seem to mean “nothing,” but one is an empty object that exists and the other is the absence of an object.
Pause and try
Question 7 · Tracing
What does this program print?
import java.util.Scanner;
public class MinutesReader
{
public static void main(String[] args)
{
Scanner times = new Scanner("40 15");
String runner = new String("Jo");
int warmUp = times.nextInt();
int coolDown = times.nextInt();
System.out.println(runner);
System.out.println(coolDown);
System.out.println(warmUp);
}
}Check your reasoning
Jo
15
40| Line | Result |
|---|---|
| 7 | times refers to a Scanner whose text is 40 15 |
| 8 | runner refers to a String holding Jo |
| 9 | warmUp is 40 (first number in the text) |
| 10 | coolDown is 15 (next number) |
| 11–13 | prints Jo, then coolDown, then warmUp |
The constructor arguments set what each object holds. Watch the print order: line 12 prints coolDown before line 13 prints warmUp.
Reread 1.13.4 Parameters Set Starting Values if your output differed.
Question 8 · Short answer
After String a = new String(); and String b = null;, how many String objects exist? Explain what each variable holds.
Check your reasoning
Model answer: One object exists. a holds a reference to a String object that has no characters, built by the String() constructor. b holds null, so it refers to no object; no constructor ran for it.
A complete answer must:
- say there is exactly one object (one
new), and - explain that an empty object still exists, while
nullmeans no object.
Reread 1.13.4 Parameters Set Starting Values if you counted two objects or none.
1.13.5 Overloaded Constructors
You have now seen two String constructors, String() and String(String original), and two Scanner constructors, one taking System.in and one taking a String. Why would a class have more than one way to build an object?
Because people want objects that start out in different ways. Sometimes you want a String with given characters; sometimes you want an empty one. Sometimes a Scanner should read the keyboard; sometimes it should read text you already have. Rather than invent a different name for each, the class offers several constructors with the same name, each with its own parameter list. This is the same idea as overloaded methods in Topic 1.9.
Constructors are overloaded when a class has more than one constructor with different signatures. Since every constructor of a class has the same name, “different signatures” means the parameter lists differ: a different number of parameters, different types, or the same types in a different order.
How does Java know which one you mean? It compares your arguments to each signature and picks the one whose parameter list matches: same number, and compatible types in the same order. That is exactly why two constructors in one class may never share a signature: Java would have no way to choose.
Key idea
Overloaded constructors share the class name but have different signatures. Java chooses which one runs by matching the call’s arguments to each parameter list.
Worked example: Which Scanner constructor runs?
This program builds two Scanner objects with two different constructors.
import java.util.Scanner;
public class TwoScanners
{
public static void main(String[] args)
{
Scanner keyboard = new Scanner(System.in);
Scanner scores = new Scanner("70 88");
int score = scores.nextInt();
System.out.println(score);
}
}Match each call to a signature:
| Line | Call | Argument type | Constructor that runs |
|---|---|---|---|
| 7 | new Scanner(System.in) |
InputStream |
Scanner(InputStream) |
| 8 | new Scanner("70 88") |
String |
Scanner(String) |
Both calls pass one argument, so the number alone cannot decide. The argument’s type decides. Line 9 reads the first number from the text-based Scanner, so the program prints:
70Now vary the number of arguments instead of the type. For String:
| Call | Number of arguments | Constructor that runs | New object holds |
|---|---|---|---|
new String() |
0 | String() |
no characters |
new String("Lake") |
1 (String) |
String(String) |
Lake |
Here the count of arguments is enough to tell the two constructors apart.
Watch out
Assuming there is a constructor for whatever you pass. Overloading gives a class several constructors, but only the ones actually written. Hoping to turn a number into text, a student writes:
String digits = new String(5);
System.out.println(digits);Java reports no suitable constructor found for String(int), then lists the String constructors it tried (including some this course never uses) and why each failed. None of them takes an int. Before calling a constructor, check that a signature matching your arguments really exists in the documentation.
Pause and try
Question 9 · Multiple choice
An invented class Lamp has three constructors:
Lamp()
Lamp(int brightness)
Lamp(String color, int brightness)Which constructor does new Lamp(75) call?
Lamp()Lamp(int brightness)Lamp(String color, int brightness)- None; the call does not compile because there are three
Lampconstructors.
Check your reasoning
B. Java picks the constructor whose parameter list matches the arguments. new Lamp(75) passes one int, which matches Lamp(int).
- A is wrong:
Lamp()takes no arguments, but this call passes one. - C is wrong: it needs two arguments, a
Stringand then anint; the call passes only one. - D is wrong: several constructors are allowed as long as their signatures differ. That is what overloading means.
Reread 1.13.5 Overloaded Constructors if you chose differently.
Question 10 · Short answer
Using the Lamp constructors from the previous question, which constructor does new Lamp("red", 40) call? Explain why new Lamp(40, "red") would not compile.
Check your reasoning
Model answer: new Lamp("red", 40) calls Lamp(String color, int brightness), because it passes a String then an int. new Lamp(40, "red") passes an int then a String; no Lamp constructor has the signature Lamp(int, String), so Java has nothing to match and reports an error.
A complete answer must:
- name
Lamp(String color, int brightness)for the first call, and - explain that order is part of matching, and no constructor takes an
intfollowed by aString.
Reread 1.13.5 Overloaded Constructors if your reasoning differed.
1.13.6 Arguments Must Match the Parameter List
A signature tells you what a constructor needs. What exactly counts as giving it what it needs, and what happens if you get it slightly wrong?
As in Topic 1.9, an argument is a value passed in when the call is made: the values between the parentheses after new Ticket. The parameters are the variables in the header that receive them. Java pairs them up by position: the first argument goes to the first parameter, the second to the second, and so on. That pairing works only if three things line up:
- Number: exactly as many arguments as parameters.
- Order: the arguments come in the same order as the parameter types.
- Type: each argument is compatible with its parameter’s type, meaning it is that type or one Java converts to it automatically. From Topic 1.5, an
intconverts to adoubleautomatically; adoublenever converts to aninton its own, because that could lose the decimal part.
Why so strict? Java pairs by position, not by meaning. It cannot tell that 14 “looks like” a seat number; it only knows the second parameter is an int.
Key idea
The arguments in a constructor call must match the parameter list in number and order, and each argument must be compatible with its parameter’s type.
Worked example: A call that matches
This version of Ticket’s constructor prints the three values it receives, so you can see the pairing.
public class TicketArguments
{
public static void main(String[] args)
{
Ticket myTicket = new Ticket("Dune", 14, 12);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.println(movie);
System.out.println(seat);
System.out.println(price);
}
}Pair each argument on line 5 with the header on line 11:
| Position | Argument | Parameter | Value the parameter gets |
|---|---|---|---|
| 1 | "Dune" |
String movie |
"Dune" |
| 2 | 14 |
int seat |
14 |
| 3 | 12 |
double price |
12.0 (int converted to double) |
Three arguments for three parameters, in the right order. The third argument is an int but the parameter is a double, which is compatible, so Java converts it. The output shows the conversion:
Dune
14
12.0Now vary the order and the count. Each of these calls is one small change from line 5 above, and none of them compiles:
| Call | What is wrong | Gist of the compiler message |
|---|---|---|
new Ticket(14, "Dune", 12.5) |
First two arguments swapped (order) | incompatible types: int cannot be converted to String |
new Ticket("Dune", 14) |
Missing the price (number) | actual and formal argument lists differ in length |
new Ticket("Dune", 12.5, 14) |
12.5 sent to int seat (type) |
incompatible types: possible lossy conversion from double to int |
The type mistake is the easiest to miss, so here it is as a full program:
public class TicketLossy
{
public static void main(String[] args)
{
Ticket myTicket = new Ticket("Dune", 12.5, 14);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.println(movie);
}
}The third argument 14 going to double price would be fine. The problem is the second: 12.5 cannot go into an int without losing .5, so Java refuses.
Watch out
Ordering arguments by what makes sense instead of by the header. Students often write the values in the order they think of them (“seat 14 for Dune”) rather than the order of the parameter list. Java matches by position only, so always check the header and line up each argument with its parameter, left to right.
Pause and try
Question 11 · Multiple choice
Ticket has only the constructor Ticket(String movie, int seat, double price). Which call compiles?
new Ticket("Up", 7.5, 3)new Ticket("Up", 3, 7)new Ticket("Up", 3)new Ticket(3, "Up", 7.5)
Check your reasoning
B. Three arguments in the order String, int, then 7, an int, which is compatible with double price and becomes 7.0.
- A is wrong:
7.5goes toint seat, and adoubledoes not convert to anintautomatically (possible lossy conversion). - C is wrong: two arguments for three parameters; the argument lists differ in length.
- D is wrong: the order is wrong;
3goes toString movie, and anintcannot be converted to aString.
Reread 1.13.6 Arguments Must Match the Parameter List if you chose differently.
Question 12 · Debugging
This program should create a ticket for seat 4 of Up costing 8.5, but it does not compile. Explain the error and write the corrected line.
public class TicketMissingPrice
{
public static void main(String[] args)
{
Ticket matinee = new Ticket("Up", 4);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.println(movie);
}
}Check your reasoning
Corrected line 5:
Ticket matinee = new Ticket("Up", 4, 8.5);The constructor needs three arguments (String, int, double), but line 5 passes only two. Java reports constructor Ticket in class Ticket cannot be applied to given types with the reason actual and formal argument lists differ in length. Adding the price as the third argument makes the number and order match. The fixed program prints Up.
Reread 1.13.6 Arguments Must Match the Parameter List if you missed it.
1.13.7 Call by Value: Parameters Get Copies
When you hand a value to a constructor and the constructor changes its parameter, does your own variable change too? It matters: if passing a variable could change it behind your back, you could never trust a variable’s value after a call.
Topic 1.9 answered this for methods, and constructors work the same way. Arguments are passed using call by value: each parameter starts out holding a copy of its argument’s value. The constructor works with its copy. Your variable and the parameter are two separate boxes that happen to start with the same value.
Picture it like photocopying a form before handing it over. Whatever the other person writes on the copy, your original stays as it was.
Key idea
With call by value, a constructor’s parameters are initialized with copies of the arguments. Changing a parameter inside the constructor does not change the caller’s variable.
Worked example: Changing the copy, not the original
In this version, the constructor adds 100 to its seat parameter. Watch mySeat in main.
public class SeatCopy
{
public static void main(String[] args)
{
int mySeat = 14;
Ticket myTicket = new Ticket("Dune", mySeat, 12.5);
System.out.print("Back in main, mySeat is ");
System.out.println(mySeat);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
seat = seat + 100;
System.out.print("Inside the constructor, seat is ");
System.out.println(seat);
}
}| Step | mySeat (in main) |
seat (in constructor) |
Printed |
|---|---|---|---|
| Line 5 | 14 | (does not exist yet) | |
| Line 6: call starts | 14 | 14 (a copy) | |
| Line 16 | 14 | 114 | |
| Lines 17–18 | 14 | 114 | Inside the constructor, seat is 114 |
Back in main, lines 7–8 |
14 | (gone) | Back in main, mySeat is 14 |
Inside the constructor, seat is 114
Back in main, mySeat is 14Only the copy changed. mySeat was never touched.
Now vary the argument: it does not have to be a variable. It can be any expression of a compatible type. Java evaluates the expression first, then passes a copy of the result.
public class SeatExpression
{
public static void main(String[] args)
{
int row = 3;
Ticket myTicket = new Ticket("Dune", row * 10, 12.5);
System.out.print("row is ");
System.out.println(row);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.print("seat is ");
System.out.println(seat);
}
}On line 6, row * 10 is evaluated to 30 before the constructor runs, and seat starts as a copy of 30. Computing the argument does not change row, so the program prints:
seat is 30
row is 3
Watch out
Thinking the parameter is the same variable as the argument. Students expect mySeat to become 114 because “it was passed in.” But the constructor never sees mySeat, only a copy of its value. The same holds even if the names match: if main’s variable were also called seat, it would still be a separate variable from the parameter seat.
Pause and try
Question 13 · Tracing
What does this program print?
public class PriceCopy
{
public static void main(String[] args)
{
double cost = 10.0;
Ticket myTicket = new Ticket("Up", 8, cost);
System.out.println(cost);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
price = price / 2;
System.out.println(price);
}
}Check your reasoning
5.0
10.0| Step | cost (in main) |
price (in constructor) |
Printed |
|---|---|---|---|
| Line 5 | 10.0 | ||
| Line 6: call starts | 10.0 | 10.0 (copy) | |
| Line 15 | 10.0 | 5.0 | |
| Line 16 | 10.0 | 5.0 | 5.0 |
Back in main, line 7 |
10.0 | (gone) | 10.0 |
The constructor halves its copy. cost keeps its value because of call by value.
Reread 1.13.7 Call by Value: Parameters Get Copies if your output differed.
1.13.8 Constructor Calls and the Flow of Control
In the last example, the constructor’s line printed before main’s next line, even though it sits lower in the file. Why? Because of the order in which the statements actually run.
Back in Topic 1.1, statements ran one after another, top to bottom. Topic 1.9 added an exception: a method call jumps into the method, runs it, and comes back. A constructor call does the same thing. When Java reaches new Ticket(...), it pauses the current statement, runs every statement in the constructor in order, and once the last one finishes, control returns to the point right after the call: it finishes the paused statement (storing the reference) and moves on to the next line. The order in which statements run is called the flow of control.
It is like pausing a video to answer the door. You deal with the visitor completely, then resume the video exactly where you stopped, not from the beginning.
Key idea
A constructor call interrupts the normal top-to-bottom order: the constructor’s statements all run first, then control returns to the point just after the call.
Worked example: Following the jump
The letters in the messages show the order in which they print. Predict the output before reading on.
public class ConstructorFlow
{
public static void main(String[] args)
{
System.out.println("A: before the constructor call");
Ticket myTicket = new Ticket("Dune", 14, 12.5);
System.out.println("D: after the constructor call");
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.println("B: constructor starts");
System.out.println("C: constructor ends");
}
}| Order | Line running | Where | Printed |
|---|---|---|---|
| 1 | 5 | main |
A: before the constructor call |
| 2 | 6 | main: call |
(jump into the constructor) |
| 3 | 15 | constructor | B: constructor starts |
| 4 | 16 | constructor | C: constructor ends |
| 5 | 6 | main: resumes |
(reference stored in myTicket) |
| 6 | 7 | main |
D: after the constructor call |
A: before the constructor call
B: constructor starts
C: constructor ends
D: after the constructor callNow vary the number of calls. Each new makes its own jump, and each jump returns to just after its own call:
public class TwoTickets
{
public static void main(String[] args)
{
Ticket first = new Ticket("Dune", 14, 12.5);
System.out.println("Between tickets");
Ticket second = new Ticket("Up", 3, 9.0);
System.out.println("Done");
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.print("Printing ticket for ");
System.out.println(movie);
}
}Line 5 jumps into the constructor (printing the ticket for Dune), comes back, and line 6 runs. Line 7 jumps in again with different arguments, comes back, and line 8 runs.
Printing ticket for Dune
Between tickets
Printing ticket for Up
Done
Watch out
Reading the file top to bottom as the run order. The constructor’s code sits below main in the file, so students sometimes predict that its lines print last, or not at all. Code in a constructor runs only when a call reaches it, and it runs right then. Trace by following the calls, not the line numbers on the page.
Pause and try
Question 14 · Tracing
What does this program print?
public class MovieNight
{
public static void main(String[] args)
{
System.out.println("Line up");
Ticket mine = new Ticket("Up", 5, 9.0);
System.out.println("Buy popcorn");
Ticket yours = new Ticket("Up", 6, 9.0);
System.out.println("Find seats");
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.print("Ticket ");
System.out.println(seat);
}
}Check your reasoning
Line up
Ticket 5
Buy popcorn
Ticket 6
Find seatsLine 5 prints Line up. Line 6 jumps into the constructor, which prints Ticket 5, then returns. Line 7 prints Buy popcorn. Line 8 jumps in again and prints Ticket 6. Line 9 prints Find seats. Each constructor call finishes completely before the next line of main runs.
Reread 1.13.8 Constructor Calls and the Flow of Control if your output differed.
Putting it together
A box-office program reads a seat number and price from a Scanner and books a ticket. It uses every idea from this chapter. (A text-based Scanner stands in for the keyboard so the output is always the same.)
import java.util.Scanner;
public class BoxOffice
{
public static void main(String[] args)
{
Scanner order = new Scanner("14 12");
String movie = new String("Dune");
int seatNumber = order.nextInt();
int dollars = order.nextInt();
Ticket booked = null;
System.out.println("Booking...");
booked = new Ticket(movie, seatNumber, dollars);
System.out.print("Done. seatNumber is still ");
System.out.println(seatNumber);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
System.out.print("Ticket for ");
System.out.println(movie);
seat = seat + 1;
System.out.print("Seat ");
System.out.println(seat);
System.out.print("Price ");
System.out.println(price);
}
}| Order | Line(s) | What happens | Printed |
|---|---|---|---|
| 1 | 7 | new calls Scanner(String) (overloading: the argument is a String); order refers to a Scanner reading 14 12 |
|
| 2 | 8 | new calls String(String); movie refers to a String holding Dune |
|
| 3 | 9–10 | seatNumber is 14, dollars is 12 |
|
| 4 | 11 | booked is declared with type Ticket and holds null: no ticket yet |
|
| 5 | 12 | prints | Booking... |
| 6 | 13 | Arguments match Ticket(String, int, double) in number and order; dollars (an int) is compatible with double |
(jump into the constructor) |
| 7 | 23–24 | movie parameter holds a copy of the reference to “Dune” |
Ticket for Dune |
| 8 | 25–27 | seat starts as a copy of 14 and becomes 15 |
Seat 15 |
| 9 | 28–29 | price is 12.0 |
Price 12.0 |
| 10 | 13 | Control returns; the new object’s reference replaces null in booked |
|
| 11 | 14–15 | seatNumber is unchanged by call by value |
Done. seatNumber is still 14 |
Booking...
Ticket for Dune
Seat 15
Price 12.0
Done. seatNumber is still 14
Three objects were created, one per new: a Scanner, a String, and a Ticket.
Vocabulary
| Term | Definition | Example |
|---|---|---|
| constructor | Code in a class, with the same name as the class, that runs to create a new object | String(String original) |
new |
The keyword placed before a constructor call to create a new object | new Scanner(System.in) |
| instantiation | Creating an object (an instance) of a class | new String("Hi") |
| reference | What a reference-type variable holds: in effect, the address of an object | city holds the address of “Denver” |
null |
A special value meaning a reference variable refers to no object | String nickname = null; |
| parameter list | The types and names, in parentheses in a header, of the values a constructor needs | (String movie, int seat, double price) |
| signature | The constructor’s name plus the ordered list of parameter types | Ticket(String, int, double) |
| overloaded | Describes constructors of one class that share a name but have different signatures | String() and String(String) |
| argument | A value passed to a constructor when it is called | "Dune" in new Ticket("Dune", 14, 12.5) |
| compatible | An argument that is the parameter’s type or converts to it automatically | 12 passed to double price |
| call by value | Passing arguments by giving each parameter a copy of the argument’s value | Changing seat leaves mySeat alone |
| flow of control | The order in which statements actually run | Constructor lines run before the next line of main |
Chapter summary
- An object is created by writing
newfollowed by a call to one of the class’s constructors, which always have the same name as the class. The result is a reference to the new object. - A reference variable must be declared with the object’s class as its type. It holds a reference to an object of that type, or
nullwhen there is no object. - A constructor’s signature is its name plus the ordered list of parameter types; parameter names are not part of it. A class can have several overloaded constructors with different signatures, and Java picks the one whose parameter list matches the arguments.
- Constructor parameters receive values that set the new object’s starting values. The arguments must match the parameter list in number and order and be compatible in type.
- Arguments are passed call by value: parameters get copies, so changing a parameter never changes the caller’s variable. A constructor call jumps into the constructor, runs all its statements, then returns to just after the call.
Review questions
Question 15 · Multiple choice
A program has import java.util.Scanner; at the top. Which statement correctly creates a Scanner that reads from the keyboard and stores it so the program can use it later?
Scanner keyboard = Scanner(System.in);String keyboard = new Scanner(System.in);Scanner keyboard = new Scanner(System.in);new Scanner(System.in);
Check your reasoning
C. It uses new with a Scanner constructor and stores the reference in a variable whose type matches the class.
- A is wrong: without
new, Java looks for a method namedScannerand reportscannot find symbol. - B is wrong: a
Stringvariable cannot hold a reference to aScanner; Java reportsincompatible types: Scanner cannot be converted to String. - D is wrong: it does build a
Scanner, but the reference is not stored anywhere, so the program can never use that object.
Reread 1.13.1 Constructors and the new Keyword and 1.13.2 Reference Variables and null if you chose differently.
Question 16 · Short answer
Kai writes Ticket saved = null; and says, “This creates a Ticket object that has no information in it yet.” Is Kai right? Explain, using what null means and what has to happen for an object to be created.
Check your reasoning
Model answer: Kai is wrong. No object is created, because there is no new and no constructor call; only a constructor called with new builds an object. The line declares a variable of type Ticket and gives it the value null, which means it refers to no object at all. (An object with no information would be something like new String(), which is a real, empty object.)
A complete answer must:
- say that no object exists, because no constructor ran (no
new), and - explain that
nullmeans “no object,” which is different from an empty object.
Reread 1.13.2 Reference Variables and null and 1.13.4 Parameters Set Starting Values if your reasoning differed.
Question 17 · Multiple choice
An invented class Song already has the constructor Song(String title, int seconds). Which constructor could not be added to the same class?
Song(String title)Song(int seconds, String title)Song(String name, int length)Song(String title, int seconds, String artist)
Check your reasoning
C. Its signature is Song(String, int), exactly the same as the existing constructor’s. Parameter names are not part of a signature, so Java would see two constructors it cannot tell apart and report that the constructor is already defined.
- A can be added: one parameter instead of two gives the signature
Song(String). - B can be added: the same types in a different order give
Song(int, String), a different signature. - D can be added: three parameters give
Song(String, int, String).
Reread 1.13.3 Reading a Constructor Signature and 1.13.5 Overloaded Constructors if you chose differently.
Question 18 · Short answer
Ticket has only the constructor Ticket(String movie, int seat, double price). Explain why new Ticket("Up", 9, 6) compiles but new Ticket("Up", 9.0, 6) does not, even though both use the same three numbers.
Check your reasoning
Model answer: Arguments are matched to parameters by position, and each must be compatible with its parameter’s type. In the first call, 9 goes to int seat (a match) and 6 goes to double price; an int converts to a double automatically, so price becomes 6.0. In the second call, 9.0 is a double going to int seat. Java does not convert a double to an int automatically, because the decimal part could be lost, so it reports a possible lossy conversion.
A complete answer must:
- explain that arguments pair with parameters by position, and
- say
inttodoubleis allowed automatically butdoubletointis not.
Reread 1.13.6 Arguments Must Match the Parameter List if your reasoning differed.
Question 19 · Debugging
This program should read the first number from the text 5 9 and print it. Line 7 has two errors. Find both and write the corrected line.
import java.util.Scanner;
public class ReaderMistakes
{
public static void main(String[] args)
{
String reader = Scanner("5 9");
int first = reader.nextInt();
System.out.println(first);
}
}Check your reasoning
Corrected line 7:
Scanner reader = new Scanner("5 9");Error 1: new is missing. Without it, Java treats Scanner("5 9") as a call to a method named Scanner and reports cannot find symbol with symbol: method Scanner(String).
Error 2: the variable type is wrong. The object being built is a Scanner, so the variable must be a Scanner. If you add new but keep String reader, Java reports incompatible types: Scanner cannot be converted to String. The compiler also flags line 8, because a String variable cannot read numbers the way a Scanner can; fixing line 7 clears that too.
With both fixes, the program prints 5.
Reread 1.13.1 Constructors and the new Keyword and 1.13.2 Reference Variables and null if you found only one error.
Question 20 · Tracing
What does this program print? Track seat in main separately from the parameter seat.
public class Matinee
{
public static void main(String[] args)
{
int seat = 20;
System.out.println("Start");
Ticket early = new Ticket("Up", seat, 7.0);
System.out.println(seat);
Ticket late = new Ticket("Dune", seat + 1, 7.0);
System.out.println(seat);
}
}
class Ticket
{
Ticket(String movie, int seat, double price)
{
seat = seat * 2;
System.out.print(movie);
System.out.print(" ");
System.out.println(seat);
}
}Check your reasoning
Start
Up 40
20
Dune 42
20| Order | Line running | seat in main |
parameter seat |
Printed |
|---|---|---|---|---|
| 1 | 5 | 20 | ||
| 2 | 6 | 20 | Start |
|
| 3 | 7: first call | 20 | 20 (copy) | |
| 4 | 18–21 | 20 | 40 | Up 40 |
| 5 | 8 | 20 | (gone) | 20 |
| 6 | 9: seat + 1 is 21 |
20 | 21 (copy) | |
| 7 | 18–21 | 20 | 42 | Dune 42 |
| 8 | 10 | 20 | (gone) | 20 |
Each call jumps into the constructor and back. The parameter has the same name as main’s variable but is a separate variable holding a copy, so doubling it never changes main’s seat. On the second call, seat + 1 is evaluated to 21 before the copy is made.
Reread 1.13.7 Call by Value: Parameters Get Copies and 1.13.8 Constructor Calls and the Flow of Control if your output differed.
Reflection
- I can create an object using new and a constructor, and say why the constructor has the class name. Reread
- I can declare a variable of the right type for an object, and explain what null means. Reread
- I can write the signature of a constructor from its header. Reread
- I can explain how constructor arguments set a new object’s starting values. Reread
- I can tell which overloaded constructor a call will use. Reread
- I can check whether a call’s arguments match in number, order, and type. Reread
- I can explain why changing a parameter does not change the caller’s variable. Reread
- I can trace the order of output when a constructor call jumps into the constructor and back. Reread