Concepts / Objects and Class Fields in Java

Objects and Class Fields in Java

Declaring Student[] classlist and creating it with new Student[30] makes an array of references, not thirty Student objects.

  • Programming

A Class of Thirty Students

Suppose a program needs to track thirty students in one class. An array is the natural tool, because an array stores many values of one type under a single name and reaches each value through a numeric index. Up to now that type has usually been a primitive such as int or double. An array of objects follows the same pattern, except each element is an object of a class you have written, such as Student. One variable can then stand for the whole class, and you can reach any one student by writing an index in square brackets.

What do you think happens?

Suppose Student[] classlist = new Student[30]; has just run, and no loop has filled the array yet. What does classlist[3] refer to? Is it a Student object, something else, or nothing at all? Commit to an answer before reading on.

  • A Student object with default values

  • Something other than a Student, such as a number

  • Nothing at all, which Java represents as null

Reveal answer
Answer:

Nothing at all, which Java represents as null.

The statement new Student[30] creates thirty positions, but each position is a reference that does not yet point to a Student. No Student object has been created by that statement. Only the loop, which calls new Student() at each index, creates the objects.

Declaring and Creating the Array

The work has two statements. The first declares a variable named classlist that can refer to an array of Student objects. The second creates an array with thirty positions and makes classlist refer to it. The source describes the result as the variable now pointing to an array. That array is a container of thirty references to Student objects, and at this stage none of those references points to a Student yet.

java
Notes on the code
  • Student[] declares a variable whose element type is the class Student
  • new Student[30] creates thirty empty positions for references to Student
classlistvariable of type Student[]array of 30 slotscontainer of references[0]null[1]null[2]null[3]nullrefers topositionpositionpositionposition
After new Student[30] runs, what exists: thirty Student objects, or thirty empty slots that can each hold a reference to a Student? The diagram shows the first four of the thirty slots.

The diagram makes the key point visible. The variable classlist leads to the array, and the array holds positions. Each position is a reference that can point to a Student. Creating the array gives you the positions, not the students themselves. Keeping the variable and the array apart is useful: the variable is the name you use to reach the array, and the array is the container of references it points to.

Tracing the Empty Slots

Now trace what happens if the program uses an element before filling it. This is where many beginners lose track of the program state. The code below creates the array and then immediately tries to use the first slot. No loop has run, so the first slot still holds nothing.

java
Output
NullPointerException: classlist[0] is null, so there is no object whose name can be read
Notes on the code
  • The array exists with 30 positions
  • Position 0 holds null, not a Student
  • The dot asks a Student object for its name, but there is no object
Student[] classlistdeclarednew Student[30]array of 30 empty slotsclasslist[0]nullclasslist[0].namefails, no object to readthenslot is still nulldot reaches for an object
Why does classlist[0].getName() fail right after new Student[30], and at which step does the slot go from expected object to null? The chain of steps runs left to right.

The failure happens at the step where the slot is read, not where the array was created. The creation step ran without error and produced thirty positions. Position 0 changed from nothing to an object only if a later step assigns an object to it. Since no such step has run, the dot cannot reach a Student, and the expression stops there.

Filling Every Slot with a Loop

Because each element must be initialized separately, the usual pattern is a loop that runs over every index and stores a new object in each position. The declaration and creation come first, and the loop follows. The loop variable i runs from 0 up to, but not including, 30, so it visits each valid index exactly once. The valid indexes are 0 through 29.

Code walkthrough
Student[] classlist = new Student[30];
for (int i = 0; i < 30; i++) {
    classlist[i] = new Student();
}
  1. 1
    Line 1 declares the variable and creates thirty empty positions
  2. 2
    The for loop starts with i equal to 0
  3. 3
    The condition i < 30 stops the loop before i reaches 30
  4. 4
    Each pass calls new Student() and stores the result at position i
  5. 5
    The increment i++ moves to the next index after each pass
  • Each position is assigned exactly once
  • The last index visited is 29, which is length minus one
i = 0classlist[0] set to newStudent()i = 1classlist[1] set to newStudent()i = 2classlist[2] set to newStudent()continue to i = 29one slot per passi = 30loop stops, all 30 slotsfilledi++i++i++condition fails
How does each loop iteration change one array slot from null to a new Student object? The diagram shows the first iterations and the final state.

After the loop finishes, every position from 0 to 29 refers to its own Student object. The array now matches the picture of a class of thirty students: one variable, thirty positions, and each position leading to a student. Notice that the loop does two jobs at once. It creates each object with new Student(), and it stores the reference in the matching slot. Skipping either part leaves a slot empty.

Using an Object Through Its Index

After initialization, classlist[i] behaves like any other variable of type Student. The index selects which object to work with, and the dot selects a field or method of that object. To read the name of student number 3, write classlist[3].name. To compute the average for student number i, call classlist[i].getAverage().

Worked example

Reading and Updating One Student

Given the filled classlist array, set the name of student number 5 to Ana, then read the name of student number 3.

  1. 1
    Pick the slot

    classlist[5] reaches the reference stored at position 5 of the array.

  2. 2
    Follow the reference

    That reference leads to one Student object, the fifth student created by the loop.

  3. 3
    Call the method

    classlist[5].setName("Ana") sends the call to that object only. Other slots are unchanged.

  4. 4
    Read a field

    classlist[3].name reaches the object at position 3 and reads its name field.

Result

Student 5 is now named Ana, and classlist[3].name returns the name of the third student in the array, which is a different object.

java
Notes on the code
  • The loop fills every slot first, so index 5 and index 3 are valid
  • setName is called on the object stored at index 5 only
  • The field read uses index 3, a different object

Read the expression from left to right, as the source suggests. The array variable is the starting point. The index chooses one stored reference, that reference leads to a Student object, and the dot then reaches into that object. Each step depends on the one before it, so a failure at an early step, such as an unset position, stops the whole expression.

Mistakes That Produce Wrong Results

  • Common mistake

    Assuming new Student[30] creates thirty Student objects

    What it looks like
    Student[] classlist = new Student[30];
    classlist[0].name is used right away
    Why it fails

    The statement creates thirty reference positions. None of them points to a Student yet, so the dot has no object to reach.

    Do this instead

    Create each object separately, usually with a loop that stores new Student() at each index.

  • Common mistake

    Looping to the wrong bound

    What it looks like
    for (int i = 0; i <= 30; i++) classlist[i] = new Student();
    Why it fails

    Valid indexes run from 0 through 29. Index 30 does not exist in a thirty-element array, so this loop goes one step past the end.

    Do this instead

    Use i < 30, which visits each valid index exactly once.

  • Common mistake

    Skipping the assignment step

    What it looks like
    for (int i = 0; i < 30; i++) { new Student(); }
    Why it fails

    The object is created but never stored in a slot, so every position stays null.

    Do this instead

    Store the new object at the matching index, as in classlist[i] = new Student();.

  • Common mistake

    Checking the rest of a long expression before confirming that the slot holds an object

Diagnosing a Diverging Result

When a result differs from what you expected, work through the program in order. The source recommends checking the declaration, the loop bounds, and whether each index has been assigned an object before checking the rest of the expression. Each check narrows the place where the state went wrong.

  1. 1
    Check the declaration: is the variable's element type Student, and was the array created with new Student[30]?
  2. 2
    Check the loop bounds: does the loop start at 0 and stop before 30, so every index from 0 to 29 is visited?
  3. 3
    Check the assignments: does each pass store a new Student at its index, rather than only creating one?
  4. 4
    Only then check the rest of the expression, such as the field read or the method call.
MEDIUM

A program declares Student[] classlist = new Student[30]; and then runs a loop that calls classlist[i] = new Student(); for i from 0 up to 29. Later the program calls classlist[30].setName("Ben"). Predict the state of the program at that last line. Which slot is reached, and what does the program do?

Hints
  • Count the valid indexes for a thirty-element array
  • Ask whether index 30 has a position in the array at all

Key Takeaways

  • Declaring Student[] classlist and creating it with new Student[30] makes an array of references, not thirty Student objects.
  • Each element must be initialized separately, usually with a loop from index 0 through 29 that stores new Student() at each position.
  • After initialization, classlist[i] works like any Student variable: classlist[3].name reads a field and classlist[i].getAverage() calls a method.
  • When a result differs from what you expected, check the declaration, the loop bounds, and whether each index holds an object before checking the rest of the expression.