AlgoMaster Logo

static Keyword

High Priority19 min readUpdated June 2, 2026
Listen to this chapter
Unlock Audio

So far, almost every field and method you've written has belonged to a specific object. Each Cart has its own items, each Customer has their own email. But some data and behavior don't belong to any single object. There's only one running count of how many Product instances have ever been created. There's only one applyTax helper, and it doesn't need a particular order to do its job. The static keyword is how Java lets you put fields and methods on the class itself rather than on every instance.

What static Actually Means

A regular (non-static) member belongs to each object. Build ten Product instances and you get ten copies of every instance field, one per object. A static member is different: it belongs to the class itself, and there is exactly one copy of it shared across every instance.

The class is a kind of container that exists once in memory. Instance fields live inside each object built from the class. Static fields live inside the container, alongside the methods and the class metadata. Every access to the class sees the same shared storage.

The three Product objects each have their own name and price. The class itself owns productCount and applyTax. Every object can reach the class-level storage, but there is only ever one copy of it, no matter how many products you build.

The same idea applies whether you're talking about fields or methods. A static field is one shared variable. A static method is one function that runs without needing any particular instance.

Static Fields

A static field is declared with the static keyword in front of the type. Once declared, it lives in one place and every line of code in the program that mentions it is reading from or writing to the same memory.

productCount is one slot. Each constructor reads its current value, adds 1, and writes back. By the time main prints, three constructor calls have each bumped that single shared counter, so it reads 3.

Compare this to the same code with an instance field instead of a static field.

Every object got its own counter, and each constructor only bumped that object's copy. The class never had a single shared total. A counter that exists per-object isn't really a counter at all, it's just a yes/no flag for "did this object's constructor run".

Static fields are useful whenever the data conceptually belongs to the class as a whole:

  • A counter of how many instances exist.
  • A registry of all objects ever created, so other code can look one up.
  • A shared cache or lookup table.
  • A configuration value like a tax rate that's the same for every order in the system.

Both carts pick up the new TAX_RATE the instant it changes, because both reach into the same single slot on the class. There's no per-cart copy to update.

A constant rate like this is exactly the kind of value you'd write as static final to lock it in. Here's a one-liner taste so you see the idiom.

The final keyword marks TAX_RATE as a one-time assignment. Once set, no code can reassign it, and the compiler enforces that at every call site. The shape (static final constant at the top of the class) is common across Java codebases.

A static field is read and written from anywhere in the program, including from multiple threads at the same time. In single-threaded code, this is safe. Once threads enter the picture, shared mutable state on a class becomes a hazard and needs synchronization. Keep mutable static fields rare. Use static final constants whenever the value never has to change.

Static Methods

A static method is declared the same way: put static in front of the return type. The method belongs to the class, not to an instance. You don't need an object to call it.

applyTax and applyDiscount don't depend on any particular cart or product. They take everything they need as parameters and return a result. That's the classic shape of a static method: pure logic with no per-object state.

Library helpers you've already used follow this same pattern:

  • Math.max(a, b) returns the larger of two numbers without needing a Math instance.
  • Math.round(price) rounds a value the same way every time.
  • Integer.parseInt("42") converts a string into an int.
  • String.valueOf(99.95) turns any value into its string form.

None of those require building an object first. The class name plus the method name is the full call.

A static method is also the natural home for a factory method, a method whose job is to build and return a new object. Factories let you give the construction step a meaningful name and run a little setup logic before handing the object back.

The factory names (empty, withSubtotal) read more clearly at the call site than two unlabeled constructor overloads would. Reading Cart.empty("Alice") tells you immediately what kind of cart you're getting.

Calling Static Members

You can call a static method or read a static field in two ways: through the class name, or through any instance of the class. They both compile, but they aren't equally good.

Both a.productCount and b.productCount read the same shared slot, so they give the same number. So does CallStyles.productCount. But a.productCount looks like it's reading something stored inside a, which it isn't. The instance variable doesn't actually matter; the compiler resolves the access on the type of a, not on the object itself. You can prove that by reading a static field through a null reference: the read still works because the object is never touched.

The convention is firm: always use `ClassName.member` to access static members. It makes the static nature obvious at the call site. A reader scanning CallStyles.productCount sees the class right there in the expression and knows the field is shared, not per-object. Most IDEs warn when you use the instance form.

If productCount were an instance field, that line would throw NullPointerException. Because it's static, the access never goes through the reference. That's a quirk, not a feature to use. Always prefer the class-name form.

Same result, but now the code says what it means.

What Static Methods Can and Cannot Do

A static method runs without an instance. There is no this available inside it, because no object called the method. That single fact drives every restriction on static methods.

Inside a static method, you cannot:

  • Use this. There is no current object.
  • Read or write an instance field directly. Those fields belong to a specific object, and the static method doesn't know which one.
  • Call an instance method directly. Same reason.

You can:

  • Read and write any static field of the class.
  • Call any other static method of the class.
  • Use any object that's handed to you (as a parameter, a local variable, or a static field).

A class that respects those rules:

getTotalUnits reads only the static field, which is fine. printStock reads productName and unitsInStock through the report parameter. That works because the method has an explicit object to look at. It would not work if you tried to read productName with no object reference, because the method has no implicit "current" product.

What's wrong with this code?

The compiler refuses:

printStock is static, so no object was passed in. There is no current instance whose productName could be read. The fix is to either pass the object explicitly, or make printStock an instance method.

Fix:

Now printStock has a specific FixedReport to look at, passed in as a parameter. The static method's "no current instance" rule still holds, but the rule doesn't say a static method can't work with objects at all. It says it can't work with an implicit one.

Another common version of the same mistake involves this.

What's wrong with this code?

The error reads:

this means "the object whose method is running". A static method isn't running on any object, so there's nothing this could refer to. The fix follows the same pattern as before.

Fix:

Pass the object in explicitly. If you find yourself doing this often, it's a sign the method probably wants to be an instance method, not a static one.

There's no rule in the other direction. An instance method can read and write static fields, call static methods, and use this. Static members are accessible from everywhere, including from inside instance methods.

printSummary is an instance method, so it can read both instance fields (orderId, total) and the static field (orderCount). The static counter doubles as an auto-incrementing ID generator, a common pattern in early prototypes.

Where Static Fields Live in Memory

A static field is stored once per class, in a region of memory associated with the class itself. Instance fields live inside each object on the heap. Static fields live in class-level storage that the JVM creates when the class is loaded.

A class is loaded the first time the program needs it: the first time you create an instance, call a static method, or read a static field. At that moment, the JVM reads the class file, sets aside the class-level storage, and runs the initializers for every static field in source order.

The static area is created once. From there on, every access to a static field on that class reads the same slot, and every static method runs against the same shared state. Instance fields, by contrast, get fresh storage every time you call new.

The deep details of class loading and where exactly the class-level storage lives in the JVM are a topic of their own. The takeaway:

  • Static fields are initialized once, when the class is loaded.
  • They live for the entire run of the program (unless the class is unloaded, which is rare).
  • All instances see the same shared slot.

For more elaborate setup than a single initializer expression can handle, for example, populating a static lookup table from a loop, static initializer blocks are appropriate. They run at class-load time, in the same step as the field initializers.

When to Use static

Use static when the field or method belongs to the class as a whole, not to any particular instance.

Use static forDon't use static for
Utility/helper methods that compute from arguments aloneMethods that need data from a specific object
Counters, registries, caches shared across all instancesPer-object state like name, email, cart contents
Factory methods that build and return objectsBehavior that varies between instances
Constants (static final values)Anything that should be different for each instance

A few concrete e-commerce examples that fit cleanly:

  • Product.productCount keeps track of how many products have been created.
  • Cart.applyTax(amount, rate) computes a tax without needing a cart.
  • Order.nextOrderId() returns the next ID from a shared counter.
  • Cart.empty(customerName) is a factory that builds an empty cart.
  • Cart.TAX_RATE is a shared constant used by every cart.

A few that shouldn't be static:

  • cart.addItem(product) belongs to a specific cart.
  • order.markShipped() belongs to a specific order.
  • customer.applyLoyaltyDiscount() depends on this customer's loyalty points.

The simplest test: would the method ever need different behavior depending on which object called it? If yes, it's an instance method. If the only inputs are the arguments, it's a static method.

There's only one running ID counter for the whole program, so a static field and a static method are appropriate. Hanging the counter off a specific OrderIdGenerator instance would complicate things, since the counter has nothing to do with any one generator.

A Worked Example

A small program that uses static fields and methods alongside instance state. The class tracks how many Order objects have been created, generates new IDs from a shared counter, and offers a static helper for computing totals with tax.

Three details:

  • orderCount and TAX_RATE are shared. Each constructor reads and updates the same counter, and every receipt reads the same tax rate.
  • withTax is a static helper called from inside an instance method (printReceipt). Instance methods can freely call static ones.
  • howManyOrders and withTax are called through Order. from main. That makes their static nature visible to anyone reading the code.

Putting withTax inside printReceipt and calling it without an instance works because both methods live in the same class. The class-name form (Order.withTax) is more explicit, especially when reading code from outside the class.

Quiz

static Keyword Quiz

5 quizzes