static: shared by all
As you already know, a method marked static belongs to the blueprint itself, not to a house. Fields can be like that too. Imagine the blueprint has a line saying "houses built", and each crew adds one to it after building. There is one such line for the whole blueprint. If each house had its own, every house would say "1".
A program often needs a shared value like this: how many objects were created, which number to give the next one. Let's see how to do it:
public class Main {
public static void main(String[] args) {
House a = new House();
House b = new House();
System.out.println(House.count); // 2
}
}
class House {
static int count;
int number;
House() {
number = ++count;
}
}Let's go through the program step by step:
static int count;is one field for the whole classHouse, and it holds0from the start.int number;is an ordinary field: each house has its own.- The constructor runs
number = ++count;. The expression++countfirst adds one to the sharedcountand then gives the new value, which goes into this house'snumber. - The first house gets number
1, the second gets2, and after twonewcallscountis2. House.countreads the field through the class name and prints2.
The houses have different numbers, but the counter is shared:
System.out.println(a.number); // 1
System.out.println(b.number); // 2
new House();
System.out.println(House.count); // 3The line new House(); builds a house and stores the reference nowhere. That is allowed: the constructor still runs, and count grows to 3.
A static field
A static field is a field marked static: there is one for the whole class, however many objects there are. Let's compare the two kinds of fields:
| An object's field | A static field | |
|---|---|---|
| Declaration | int number; | static int count; |
| How many copies | one in each object | one for the whole class |
| How to reach it from outside | through an object: a.number | through the class: House.count |
| When it appears | with each new | when the JVM loads the class, before the first object |
Inside its own class, a static field is reached by its bare name, like count in the constructor. This is why the fields and methods next to main have been written with static so far. Nobody created an object of the class Main, so only what belongs to the class itself could be used.
Here the blueprint picture is not exact. Only the crew corrects the line on a real blueprint, but a static field without private can be changed by any code in the program: House.count = 100; compiles.
A static method
A static method belongs to the class too, and you call it through the class name: Math.addExact(2, 3) is a static method of the class Math. There is no object in such a call, and so there is no this either. That is why a static method cannot read an object's field:
class House {
static int count;
int number;
static void show() {
System.out.println(number); // ✗
}
}error: non-static variable number cannot be referenced from a static contextThe program does not compile. The call House.show() does not say which house it is about, so whose number to print is unknown. But show can read count: that field is one for the whole class. A static method works with an object's field only if it gets the object itself, as a parameter or through new.
Interviewers often ask why a static method cannot reach an object's field. The answer: a static method has no this, that is, no object whose field it could read.
Common mistake
The compiler says non-static variable … cannot be referenced from a static context, and the field is made static to make the error go away. The error goes, and so does the meaning of the field:
public class Main {
public static void main(String[] args) {
House a = new House("red");
House b = new House("blue");
System.out.println(a.color); // blue
}
}
class House {
static String color; // ✗
House(String color) {
this.color = color;
}
}The program prints blue, although the house a was built red. The field color is one for the whole class, and the second constructor overwrote it. Plain javac says nothing, and only javac -Xlint:all warns that a static field is reached through an object. A color belongs to a particular house, so static has no place here: String color;.
Key points
- A static field is one for the whole class: all objects share it, and from outside you reach it through the class,
House.count. - A field without
staticis each object's own:a.numberandb.numberhold different numbers. - A static method has no
this, so it can read an object's field only through a reference to the object. staticon a field that should belong to each object makes it shared: every house gets one color.