Instance Methods and Object State
An instance variable can receive an initial value directly in its declaration, such as public int die1 = 3;, and that value is the starting value of each new object.
Why a New Object Already Holds Values
Every object you create begins its life with some values stored in its fields. Consider a program that models a pair of dice. Each pair needs two numbers, one for each die, and those numbers must already have a value the moment the pair exists. Someone reading the class needs to know what those starting values are, and so does anyone debugging a program that seems to show the wrong number.
This article follows one class from its source code through to the values an object actually holds, and it shows where those values come from. The answer comes straight from the declarations. Before you read on, make a prediction about the simplest case, where a field is declared with no value at all.
What do you think happens?
A class contains the declaration public int die1; with no initializer. What value does die1 hold in a newly created object?
Reveal answer
0
When a declaration has no initializer, Java supplies a default value based on the variable's type. For an int, which is a numeric type, the default is zero.
Tracing the Starting State of PairOfDice
Start by reading the class itself. The statement public int die1 = 3; declares an instance variable named die1 that holds an int, and it fixes that variable's starting value at 3. The declaration has the same form as any other variable declaration: you write the type, the name, an equals sign, and the starting value. Because the value is part of the declaration, a reader can see the starting state of the field without searching through the constructor or other methods.
Trace what happens when someone writes new PairOfDice(). The new object is created, and each field receives the value named in its declaration: die1 holds 3 and die2 holds 4. Nothing in the class changes those values until a method assigns something new to them. The roll() method is the only code in this class that does so, and it runs only when someone calls it. So immediately after creation, the object's state is die1 = 3 and die2 = 4, and it stays that way until roll() is called.
How Initializers Set Starting Values
An initializer is the part of a declaration after the equals sign. It is the value the field holds when the object is created. You can think of it as a rule that runs as part of creation rather than as a line of code that runs later. The same two fields can be written with or without initializers, and the difference shows up only in their starting values. The field names and types stay the same.
The diagram shows the decision Java makes for each instance variable. If the declaration includes an initializer, that value is used. If it does not, Java supplies the default for the variable's type. The diagram describes the same two fields in two versions of a class: in one version neither field has a declared value, so each receives its default, and in the other the initializers replace those defaults with 3 and 4.
Tracing Defaults When No Initializer Is Written
A declaration does not have to include an initializer. If you leave one out, Java still gives the instance variable a starting value automatically, and the value depends on the variable's type. The default values are zero for numeric types, false for boolean, the Unicode character with code number zero for char, and null for object types. String is an object type, so a String field begins as null, not as an empty string.
The rules in the map are the ones to memorize. Numeric types such as int and double start at zero. A boolean starts at false. A char starts at the zero-code character, and a variable of object type starts at null. Notice that the default depends only on the type of the field, not on anything else in the class.
0
0.0
false
0
null- count has no initializer, so it starts at 0
- price is a double with no initializer, so it starts at 0.0
- ready is a boolean, so it starts at false
- The char is cast to int to show its numeric code, which is zero
- label is a String, an object type, so it starts at null rather than an empty string
The cast on the char line is there for readability. A raw zero-code character would be hard to read on screen, so casting it to int shows its numeric code, which is 0. The output lines match the default rules: 0 for the numeric field, false for the boolean, the zero-code character for the char, and null for the String.
Mixing an Initializer With a Default
A class declares public int die1 = 3; and public int die2; with no initializer. What are the starting values of die1 and die2 in a newly created object?
- 1Check die1
The declaration includes the initializer 3, so the declared value is used. die1 starts at 3.
- 2Check die2
The declaration has no initializer. Because int is a numeric type, Java supplies the default zero. die2 starts at 0.
- 3Confirm the moment
Both values are set when the object is created. Neither changes until a method assigns a new value.
die1 starts at 3 and die2 starts at 0.
Mistakes When Reading Starting Values
Common mistake Assuming a String field starts as an empty string
What it looks likepublic String label; followed by label.length() on a new objectWhy it failsA String is an object type, so a field with no initializer starts at null. Calling a method on null causes an error rather than returning 0.
Do this insteadRead the declaration. If there is no initializer, expect null and check for it before using the field.
Common mistake Assuming every field starts at zero
What it looks likeReading a boolean field with no initializer and expecting 0
Why it failsThe default depends on the type. A boolean starts at false, a char starts at the zero-code character, and an object type starts at null.
Do this insteadLook up the default for the field's own type rather than applying one rule to every field.
Common mistake Thinking the initializer runs once for the whole class
What it looks likeExpecting a second PairOfDice to keep the values changed in the first one
Why it failsInstance variable initialization runs for every new object, so each object gets its own starting values. Only static variables are initialized once, when the class is first loaded.
Do this insteadTreat each object as having its own fields, and check the declaration for each new object rather than assuming a shared value.
Common mistake Blaming the wrong moment when a value looks wrong
What it looks likeA die shows 5 right after creation and the reader assumes the initializer is broken
Why it failsInitialization belongs to the moment the object begins. A value that changes later usually came from an assignment inside a method, such as
roll().Do this insteadAsk which moment produced the value. If the declaration has an initializer, check whether a later assignment changed it before the value was read.
Checking the Starting State
A class declares public int die1 = 3; public int die2; public String name; and public boolean active;. Without running the code, write down the starting value of each field in a newly created object. Then say which field's value comes from an initializer and which comes from a default.
Hints
- Check each declaration for an equals sign. If there is one, the value after it is the starting value.
- For fields without an initializer, look up the default for the type: 0 for int, false for boolean, and null for String.
- Remember that name is an object type, so its default is null, not an empty string.
Where Starting Values Come From
When an object is created, each instance variable receives a starting value. If its declaration has an initializer, that value is used. If not, Java supplies a default based on the type. Those starting values are kept separately for each object, and they remain until a method assigns something new.
Key Takeaways
- An initializer in a declaration, such as public int die1 = 3;, sets the starting value of that instance variable for each new object.
- Without an initializer, Java supplies zero for numeric types, false for boolean, the zero-code character for char, and null for object types including String.
- Initialization runs for every new object, so each object has its own fields; static variables are initialized once when the class is first loaded.
- When a value looks wrong, check whether the declaration has an initializer and whether a later assignment in a method changed it before it was read.