A static member belongs to the class itself, not to each instance. You call it as Money.of(5, "EUR"), not on an object.
Good uses:
- Named factory methods:
Money.of(),User.fromRow(row). They can validate input before creating the object, and the name says what they do. - Constants tied to the class:
Order.MAX_LINES = 50. - Small pure helpers that need the class's private details.
Problems:
- Static state is global. A
static cache = new Map()is shared by every request, every tenant and every test. One test can leak data into the next. - Hard to replace in tests. Code that calls
EmailClient.send()directly cannot receive a fake through the constructor. - Hidden dependencies. The constructor no longer shows everything the class uses.
Inside a static method, this is the class. Subclasses inherit static members too.
In short: static is fine for factories and constants. For anything with state or side effects, use an instance and inject it.
- Static members belong to the class, not to each instance.
- Static factory methods are a good place to validate before creating an object.
- Static mutable state is shared by every request and every test.
- Code that calls a static method directly is hard to test with a fake.