The labs on this site need JavaScript to run. The same content is written out below.
Learn › Java › Classes and objects
static and instance
Why does the value of a change when only b was touched?
When you put static in front of a field, the field exists only once, in the class and not in an object, and all objects share that one field. An instance variable, which is a field without static, is created separately for each object. A static method is called without an object, so you cannot use instance variables or this inside it.
Checked against real execution · All 30 combinations were compiled and run on JDK 21, and the compilation result and the output were checked against the results
Concepts in this lab
- static
- This keyword marks a member as belonging to the class, not to an instance. A static field exists only once per class and is shared by all instances, and a static method is called without creating an object. A static field whose value changes is effectively a global variable, so it easily causes problems when several threads access it at the same time.
- Classes and objects
- A class is a blueprint that states which fields (data) and methods (behavior) something has, and an object is the actual thing that is created in memory (on the heap) by using new with that blueprint. An object is also called an instance. You can create many objects from one class, and each object has its own field values. A variable holds not the object itself but a reference to where the object is.
- Instance members and static members
- Instance members are the fields and methods that are declared without static, and they belong to an object. An instance variable is created separately for each object, and an instance method must be called on an object, as in a.hit(). Static members belong to the class and are used without an object, as ClassName.member. A static method has no target object, so inside it you cannot use instance variables, instance methods, or this by name alone, and doing so is a compile-time error. In the other direction, an instance method can use static members freely.
- this
- This keyword is a reference to the current object: inside an instance method or a constructor, it refers to the very object that is being worked on. Writing this.name tells a field apart from a parameter with the same name. Writing this(arguments) as the first statement of a constructor runs another constructor of the same class first. A static method has no target object, so this cannot be used in it.
Try these
- Default settings — count is static. a.hit() is called twice and b.hit() once, yet both print 3.
- Without static — Each object has its own count. The output is 2 and 1.
- An instance variable used in a static method — It cannot be determined which object the count belongs to, so the result is a compile-time error.
- A static field used in a static method — The value is read with Counter.report(), without an object.
- this used in a static method — Even though count is static, this cannot be used.
- Counter.count before any object is created — A static field exists even when there are no objects at all.
- Counter.hit() without an object — An instance method cannot be called with the class name.
Running with the default settings
- Compilation: The compiler reads the declaration of Counter. count is a static field, so there is only one, in the class, and hit() is an instance method, declared without static, so it is called on an object, as in a.hit().
- Execution starts: The Counter class is made ready when it is first used. One static field count is created in the class and set to its default value, 0. There are no objects yet.
- Counter a = new Counter(): An object is created on the heap, and a refers to it. count is static, so it does not go inside the object. This object has no count of its own.
- Counter b = new Counter(): A second object is created, and b refers to it. b has no count of its own either. There is still only one count, in the class.
- a.hit(): count++ inside hit() runs. count is a static field, so the single count in the class increases by 1. The value is now 1.
- a.hit(): count++ inside hit() runs. count is a static field, so the single count in the class increases by 1. The value is now 2.
- b.hit(): count++ inside hit() runs. The method is called on b, but count is a static field, so the very same count that a.hit() incremented goes up further. The value is now 3.
- System.out.println(a.count + " " + b.count): a.count and b.count differ only in how they are written. Both read the single count in the class. When a static field is read through an object variable, the static field of Counter, the type of the variable, is read. The output is 3 3.
Result of this run
- There is only one static field, in the class, so all objects see the same value. The calls to a.hit() (2 of them) and to b.hit() (1 of them) increment the same count, so whichever object you read it through, the value is the total, 3.
- Using a static field through an object variable, as in a.count, is confusing because it looks like a value that each object has separately. As a rule, use static members with the class name, as in Counter.count.
- Make a value that must differ for each object (a name, a quantity) an instance variable, and make a value that needs to exist only once for the whole class (a constant, the number of objects created) a static field.
Code
class Counter {
static int count; // static field: one in the class
void hit() { // instance method
count++;
}
}
Counter a = new Counter();
Counter b = new Counter();
a.hit();
a.hit();
b.hit();
System.out.println(a.count + " " + b.count);
Assumptions of this model
All 30 combinations were actually compiled and run with the same code on JDK 21 on this PC, and the compilation result, the error message, and the output were checked against the results. It was also confirmed by execution that the "static method that receives an object as an argument", which the summary gives as a fix, compiles and runs, and that the object is not used when a static field is read through an object variable (no exception is thrown even when it is read through a variable that is null). Simplifications: the "class" area in the diagram lumps together the place where the JVM keeps class information, and exactly where in memory a static field is placed depends on the JVM implementation. The exact moment when the class is made ready (when an object is first created or a static member is first used) is reduced to the single step "Execution starts". Code that uses a static field through an object variable, as in a.count, compiles but is not recommended, and it is included here to show that the field is shared. The error message is the first line of the English message from javac.
Previous lab: Classes, objects, and constructors · Next lab: Inheritance and overriding