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.
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.
Reveal 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.
- Student[] declares a variable whose element type is the class Student
- new Student[30] creates thirty empty positions for references to Student
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.
NullPointerException: classlist[0] is null, so there is no object whose name can be read- 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
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.
Student[] classlist = new Student[30];
for (int i = 0; i < 30; i++) {
classlist[i] = new Student();
}- 1Line 1 declares the variable and creates thirty empty positions
- 2The for loop starts with i equal to 0
- 3The condition i < 30 stops the loop before i reaches 30
- 4Each pass calls new
Student()and stores the result at position i - 5The 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
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().
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.
- 1Pick the slot
classlist[5] reaches the reference stored at position 5 of the array.
- 2Follow the reference
That reference leads to one Student object, the fifth student created by the loop.
- 3Call the method
classlist[5].setName("Ana") sends the call to that object only. Other slots are unchanged.
- 4Read a field
classlist[3].name reaches the object at position 3 and reads its name field.
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.
- The loop fills every slot first, so index 5 and index 3 are valid
setNameis 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 likeStudent[] classlist = new Student[30]; classlist[0].name is used right awayWhy it failsThe statement creates thirty reference positions. None of them points to a Student yet, so the dot has no object to reach.
Do this insteadCreate each object separately, usually with a loop that stores new Student() at each index.
Common mistake Looping to the wrong bound
What it looks likefor (int i = 0; i <= 30; i++) classlist[i] = new Student();Why it failsValid 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 insteadUse i < 30, which visits each valid index exactly once.
Common mistake Skipping the assignment step
What it looks likefor (int i = 0; i < 30; i++) { new Student(); }Why it failsThe object is created but never stored in a slot, so every position stays null.
Do this insteadStore 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.
- 1Check the declaration: is the variable's element type Student, and was the array created with new Student[30]?
- 2Check the loop bounds: does the loop start at 0 and stop before 30, so every index from 0 to 29 is visited?
- 3Check the assignments: does each pass store a new Student at its index, rather than only creating one?
- 4Only then check the rest of the expression, such as the field read or the method call.
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.