The static and final keywords
Members that belong to the class not the object, values that never change, and constants done right.
Finished reading?
Mark this session so you can track where you are.
Members that belong to the class not the object, values that never change, and constants done right.
Finished reading?
Mark this session so you can track where you are.
Almost everything you have built so far belongs to one object. Each customer has its own balance, each box its own width. But some facts are not about any single object at all. How many customers exist? What is the tax rate everyone shares? This session is about two small keywords that answer exactly those questions: static, for what belongs to the class itself, and final, for what must never change.
static field to share one value across every object, like a count of how many exist.static method, call it on the class, and say why it cannot touch this.main has been marked static this whole time.final to make a constant, lock a method against overriding, and seal a class against extension.public static final.this points at the object a method runs on. You have also seen overriding and inheritance with extends. That is everything we need. This session adds no new kind of thing; it adds two modifiers that change who owns a member and whether it can change.Picture a small game. Every time the player spawns a goblin, a new Goblin object is born. Now the game wants to show a number on screen: how many goblins are currently alive? Each goblin knows its own id, but no goblin knows the total. The total is not a fact about any one goblin. It is a fact about goblins as a whole.
With only the tools you have, your instinct might be to add a field count to Goblin. But that gives every goblin its own private count, and each one would just hold the lonely number 1. There is no single shared box. We need a value that lives once, next to the class itself, that every goblin reads from and writes to.
Some data belongs to the class, not to any object. A count of how many objects exist is the classic example: it is one number, shared by all of them, owned by none of them.
Marking a field static says: this field belongs to the class, and there is exactly one of it, no matter how many objects you make. Every object shares that one box. So we put a static counter on Goblin, and bump it once inside the constructor. The constructor runs once per new, so the count rises by one for every goblin born.
public class Main { public static void main(String[] args) { Goblin g1 = new Goblin(); Goblin g2 = new Goblin(); Goblin g3 = new Goblin(); System.out.println("Goblins alive: " + Goblin.count); System.out.println("g2 is goblin number " + g2.id); }} class Goblin { static int count = 0; int id; Goblin() { count = count + 1; this.id = count; }}Goblins alive: 3 g2 is goblin number 2
Step through it and watch count climb. The first new Goblin() runs the constructor: count goes from 0 to 1, and that goblin saves 1 as its own id. The second new Goblin() sees the same shared count, now 1, raises it to 2, and saves 2. The third raises it to 3. At the end, Goblin.count is 3. There is only one count, and all three constructors touched it in turn.
Goblin.count, using the class name, not g2.count. Because the field belongs to the class, the natural way to reach it is through the class. Java will let you write g2.count too, but it is misleading: it looks like g2 has its own count when it does not. Prefer the class name, so the shared nature is visible.Compare this to id, which is an ordinary instance field with no static. Each goblin has its own id: g1 holds 1, g2 holds 2, g3 holds 3. Three separate boxes. The one count box is shared; the three id boxes are private. That contrast is the whole idea.
g2.id.Goblin.count.this refers to it.this. It is not about any object.Methods can be static too. A static method belongs to the class, so you call it on the class, not on an object. You have already been using static methods without naming them: Math.max(7, 3) is a static method called on the Math class. You never wrote new Math(), because max does not need an object. It just takes two numbers and gives one back. It is a pure piece of work that lives on the class for convenience.
Here is a small utility class of our own. bigger is a job, not a property of any object, so it is static. We call it as MathUtil.bigger(7, 3).
public class Main { public static void main(String[] args) { int b = MathUtil.bigger(7, 3); System.out.println("Bigger of 7 and 3: " + b); System.out.println("Bigger of 2 and 9: " + MathUtil.bigger(2, 9)); }} class MathUtil { static int bigger(int a, int b) { if (a > b) { return a; } return b; }}Bigger of 7 and 3: 7 Bigger of 2 and 9: 9
No object was ever made. We never said new MathUtil(). The class name and the method name were enough, because the work depends only on the two arguments handed in, not on any stored state. That is the signature of a good static method: give it inputs, get an output, no object required.
A static method has no object, so the word this means nothing inside it. There is no object it is running on. That leads directly to the rule: a static method cannot read an instance field, because an instance field belongs to some object, and a static method does not have one. Look at this broken attempt. report is static, but it reaches for size, an instance field. Which object's size? There is none. Java refuses.
public class Main { public static void main(String[] args) { System.out.println(Thing.report()); }} class Thing { int size = 5; // an instance field: belongs to an object static String report() { // ERROR: which object's size? A static method has no object. return "size is " + size; }}error: non-static variable size cannot be referenced from a static context
You have typed public static void main(String[] args) at the top of every program since the very beginning, on faith. Now you can read it. The static there is doing real work.
mainis the door the program enters through, and the program has no objects yet when it knocks. A staticmaincan be called on the class alone, so it works before anything else exists.
The second keyword is final. On a variable, final means: you may assign it once, and after that it can never be reassigned. Try to change it and the compiler stops you. This turns a variable into a constant, a name for a value that is fixed for good.
Why bother? Two reasons. First, safety: if a value should never change, saying so lets the compiler guard it for you, and a wrong reassignment becomes an error instead of a silent bug. Second, clarity: a reader sees final and knows this name stands for one settled thing. By convention, constants are written in UPPER_CASE with underscores, so they stand out from ordinary variables on sight.
public class Main { public static void main(String[] args) { final int LANES = 4; System.out.println("Lanes: " + LANES); LANES = 5; // ERROR: LANES is final. It was already set once. }}Lanes: 4 error: cannot assign a value to final variable LANES
LANES = 5 is rejected with the message shown. The point is to see the protection in action: once final is set, it stays.final locks the variable, the name, so it cannot be pointed at a different value. It does not freeze the object the name points at. For the simple number and text constants in this session that distinction does not bite, but file it away: a final reference to a mutable object can still have the object changed through it. You will meet that subtlety later; for now, read finalas “this name keeps its one value”.The same word, final, has two more uses, and they read the same way: this cannot change. On a method, final means a subclass cannot override it. On a class, final means no class can extend it. Both are ways of saying: I have decided how this works, and I do not want anyone redefining it underneath me.
String: it is a final class, so nobody can write class MyString extends String. That guarantee is part of why String can be trusted to behave the same way everywhere in every program.final on a method or class is a message to future readers, including future you: “this is settled, build on it, do not redefine it”. Reach for it when a guarantee matters. Do not sprinkle it everywhere out of caution; a class that should never be extended is genuinely different from one you simply have not extended yet.Now combine the two. A value that belongs to the class (so, static) and never changes (so, final) is a class constant. This is one of the most common and useful patterns in all of Java. You declare a shared, named, unchanging value once, and the whole program reads it through the class. The standard form is public static final, written in UPPER_CASE.
You have already used one: Math.PI is a public static final double on the Math class. Here is our own. TimeUtil holds the number of seconds in a day as a constant, and a static method uses it. The constant is set once, shared everywhere, and impossible to change by accident.
public class Main { public static void main(String[] args) { System.out.println("Seconds in a day: " + TimeUtil.SECONDS_PER_DAY); System.out.println("Two days in seconds: " + TimeUtil.daysToSeconds(2)); }} class TimeUtil { public static final int SECONDS_PER_DAY = 86400; static int daysToSeconds(int days) { return days * SECONDS_PER_DAY; }}Seconds in a day: 86400 Two days in seconds: 172800
Read the program. SECONDS_PER_DAY is declared once, capitalised so it announces itself as a constant, and used both from outside (in main) and inside the class (in daysToSeconds). If a stray line ever tried to write TimeUtil.SECONDS_PER_DAY = 99, the compiler would reject it, because the field is final. One source of truth, named, shared, and locked.
Constants like this also work happily inside ordinary instance methods. A shopping cart can keep its own subtotal as an instance field, while the tax rate, the same for every cart, lives once as a static final constant. Each cart reads the one shared rate.
public class Main { public static void main(String[] args) { Cart c = new Cart(); c.subtotal = 100.0; System.out.println("Tax rate (shared): " + Cart.TAX_RATE); System.out.println("Total with tax: " + c.total()); }} class Cart { static final double TAX_RATE = 0.1; double subtotal; double total() { return subtotal + subtotal * TAX_RATE; }}Tax rate (shared): 0.1 Total with tax: 110.0
Step through and notice the two kinds of data working side by side. subtotalis an instance field: this cart's own number, 100.0. TAX_RATE is a class constant: one value, 0.1, shared by every cart that will ever exist. total()reads both and returns 110.0. Give the cart a different subtotal and the total changes; the tax rate does not, because it is not this cart's to change.
public static final NAMEis the standard shape of a constant:staticso there is one, shared by the whole class, andfinalso it can never be reassigned. Capitalise it so everyone can see at a glance that it never moves.
static and final constantly from here on. Interfaces, which you met in interfaces, treat every field they declare as automatically public static final, which is exactly the constant pattern from this session. And when you reach Java's built-in libraries, you will find static utility methods and static final constants everywhere. Nothing new to learn there; you have the idea now.Try each one yourself first, then open the answer.
static does to a field and what an ordinary instance field is by contrast. Use the goblin count if it helps.g1, g2, and g3 are created, what does Goblin.count print, and what does g3.id print? Why are they not the same kind of number?static method report() inside a class that has an instance field size, and the method tries to return "size is " + size. The compiler refuses. Why, in plain words?main is marked static.final forbids: (a) final int SPEED = 5;, (b) a method marked final, (c) a class marked final.public static final double TAX_RATE = 0.1; the right shape for a shared tax rate, and what does each of the three words contribute?Take these away. They continue exactly what we just did.
BankAccount class with an ordinary instance field balance and a static field accountsOpened that starts at 0. Raise accountsOpened by one in the constructor. In main, create three accounts, then print each account's balance and finally BankAccount.accountsOpened. Confirm the shared count reads 3 while each balance stays its own.Geometry with a static final double PI = 3.14159; and a static method circleArea(double r) that returns PI * r * r. In main, print the area for a radius of 2 and a radius of 5 by calling Geometry.circleArea(...). Note that you never write new Geometry().Dog's name, (b) the total number of dogs created, (c) a method that converts inches to centimetres, (d) the number of legs every dog has (always 4).String a final class was a deliberate safety decision. What could go wrong if anyone were allowed to extend String and override its methods?