Concepts / Instance Variables and Object State

Instance Variables and Object State

A static class member, such as playerCount, belongs to the class itself and is stored as part of the class representation in memory. There is only one copy, and it exists as long as the program runs.

  • Programming

A Puzzle About Player Data

Imagine a program that describes players in a game. Each player has a name and an age, which seem to describe one particular player. But the program may also need a number that describes the game as a whole, such as how many players exist. Both kinds of data can be declared inside the same class, so a reasonable question arises: when a value is declared, who owns it, the class or each object created from the class?

What do you think happens?

Suppose a class declares one static member and two non-static members, and the program then creates two objects from that class. How many copies of the static member exist?

  • One copy, shared by the class and both objects

  • Two copies, one for each object

  • Three copies, one for the class and one for each object

Reveal answer
Answer:

One copy. The static member belongs to the class itself and is stored once as part of the class representation in memory.

The non-static members are the ones that get a separate copy for each object. The static member is not duplicated per object. Keep this answer in mind as the rest of the article shows where each member lives.

The rest of this article traces a single class through a sequence of steps. You will follow where each member is stored, watch one shared value change as objects are created, and then predict where a member can be reached from. The key idea is the one stated in the source: the single word static decides who owns a member, and that ownership decides how many copies exist.

Tracing the Three Declarations

The article uses one class throughout. It declares three members. The first, playerCount, is static. The other two, name and age, are not static. Read the declarations first, before tracing anything, because every later question refers back to them.

java
Notes on the code
  • static int playerCount: the static member; one shared value for the whole class
  • String name and int age: non-static members; each object gets its own copy
  • The constructor is included only to show when playerCount changes; the source does not describe it
  1. 1
    Look at the declaration before the type. If the keyword static is present, the member is static.
  2. 2
    If the keyword is absent, as with name and age, the member is non-static.
  3. 3
    A static member is stored as part of the class itself, so it is reached through the class name.
  4. 4
    A non-static member is stored for each object, so it is reached through an object.
PlayerData classstatic playerCount (onecopy)player1 objectname and ageplayer2 objectname and agebuilt frombuilt from
After two PlayerData objects exist, where does the static playerCount sit compared with the name and age values inside each object, and how many copies of each exist?

Read the figure as a structural map. The static playerCount appears once, attached to the class, and it does not appear inside either object. The name and age values appear inside each object and not on the class, because they are not part of the class itself. Two objects are drawn here, but the same arrangement holds for as many objects as the program creates.

The Class Owns the Static Member

A static class member, such as playerCount, belongs to the class itself and is stored as part of the class representation in memory. There is only one copy of it, and it exists for as long as the program runs. Its full name is PlayerData.playerCount. The class name is enough to reach it, and no object has to be created first.

Because a static member belongs to the class, every use of the class shares the same value. If one part of the program changes playerCount through the class name, every other part that reads playerCount sees the updated value. This is what the source means when it says a static value is shared by everything that uses the class.

A static method follows the same ownership rule. It is part of the class itself, which is why static methods are also called class methods. Static members are therefore described as class variables and class methods, in contrast with the per-object members discussed next.

Each Object Owns Its Own Instance Data

A non-static class member, such as name or age, belongs to each instance object. Every object created from the class gets its own copy of the non-static part. So player1 has its own name and age, and player2 has its own name and age, and changing one object's age leaves the other object's age untouched.

Non-static variables do not become part of the class. That is why there is no PlayerData.name and no PlayerData.age. You cannot reach these variables through the class name alone. They only exist once an object has been created, and they are then reached through that object, such as player1.name.

Best practice

When you see a non-static member in code, ask which object it belongs to before reading its value. A reference such as player1.age answers a question about one object only. A reference such as PlayerData.playerCount answers a question about the class as a whole.

Watching playerCount Change Across Objects

Worked example

Creating two players and following playerCount

Starting from the PlayerData class above, the program creates player1 with name Asha and age 20, then creates player2 with name Ravi and age 25. What value does playerCount hold after each creation, and where does each value live?

  1. 1
    Before any object exists

    The class has its single static copy of playerCount, which holds 0. No object exists yet, so no name or age exists either.

  2. 2
    After player1 is created

    The constructor creates an object with its own name (Asha) and age (20). The single shared playerCount is incremented, so the class-level value becomes 1.

  3. 3
    After player2 is created

    A second object is created with its own name (Ravi) and age (25). These values do not replace player1's values. The single shared playerCount is incremented again, so it becomes 2.

  4. 4
    Reading the values

    PlayerData.playerCount gives 2, which describes the whole class. player1.name gives Asha and player2.name gives Ravi, because each object holds its own name.

Result

playerCount is 2 and is one shared value. name and age exist twice, once inside each object.

playerCount = 0no objects yetplayerCount = 1player1 createdplayerCount = 2player2 createdcreate player1create player2
When player1 and then player2 are created, how does the single shared playerCount value change, and which objects see the updated value?

The diagram shows only the single shared value. Both player1 and player2 are aware of the same playerCount, because it belongs to the class and not to either object. Each object's name and age, by contrast, remain separate and are not shown in this progression.

Class Name Versus Object Access

The ownership rule decides how a member may be referenced. A static member can be reached through the class name, while a non-static member is reached through an object. The table summarizes the difference for the three members in the running example.

MemberKeywordBelongs toReached through the class name?Copies that exist
playerCountstaticThe class itselfYes, as PlayerData.playerCountOne
namenoneEach objectNo, there is no PlayerData.nameOne per object
agenoneEach objectNo, there is no PlayerData.ageOne per object

Ownership and access for the three members of PlayerData

Mistakes When Reading Shared and Per-Object Values

  • Common mistake

    Assuming every member is copied into each object

    What it looks like

    Believing that playerCount exists separately inside player1 and player2.

    Why it fails

    A static member belongs to the class and has only one copy, which exists as long as the program runs.

    Do this instead

    Look for the keyword static. If it is present, the value is stored once on the class and shared by all users of the class.

  • Common mistake

    Trying to reach a non-static member through the class name

    What it looks like

    Writing PlayerData.name and expecting a player's name.

    Why it fails

    Non-static variables do not become part of the class, so there is no PlayerData.name.

    Do this instead

    Reach the value through an object, such as player1.name.

  • Common mistake

    Expecting a change to one object's non-static value to affect another object

    What it looks like

    Changing player1.age and then expecting player2.age to change as well.

    Why it fails

    Each object has its own copy of the non-static part, so the other object is untouched.

    Do this instead

    Trace the change through the specific object that was modified.

  • Common mistake

    Forgetting that a static value persists while the program runs, so a value changed earlier is still present later

Many surprising results in code come from assuming one kind of storage when the code actually used the other. When a result is unexpected, a useful first question is whether the value belongs to the class or to an object.

Predicting Where a Member Lives

EASY

Using the PlayerData class from this article, decide for each of the following expressions whether it refers to the class or to an object, and state where the value is stored: PlayerData.playerCount, player1.name, player2.age, and PlayerData.name. Explain which of these would be a valid reference.

Hints
  • Check the declaration of each member: playerCount has the keyword static, while name and age do not.
  • A static member can be reached through the class name, and a non-static member is reached through an object.
  • PlayerData.name is invalid because name is not part of the class itself.
MEDIUM

A program creates three PlayerData objects and then reads PlayerData.playerCount. Without running the program, state the value you expect and explain which storage location produced it.

Hints
  • Each constructor call increments the single shared playerCount in this example.
  • The value is one shared value, not three separate values.

Key Takeaways

  • A static member, such as playerCount, belongs to the class itself, is stored once as part of the class representation, and exists for as long as the program runs.
  • A non-static member, such as name or age, belongs to each instance object, and every object created from the class gets its own copy.
  • Static members are reached through the class name, as in PlayerData.playerCount, while non-static members are reached through an object, as in player1.name.
  • When a result is unexpected, first ask whether the value belongs to the class or to an object, because that answer predicts whether changes are shared or private.