private final static attribute vs private final attribute
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.
Introduction
A private static final field in Java belongs to the class and is shared across every instance. A private final field belongs to each individual object and can hold a different value per instance. The static keyword is the only difference between the two declarations, but it changes where the value lives in memory, when it gets initialized, and what design intent the code communicates.
Choosing the wrong one does not usually cause a compiler error, but it leads to wasted memory, confusing APIs, or bugs when a value that should be constant per class accidentally varies per instance.
What Each Modifier Does
Before comparing the two combinations, it helps to be precise about each keyword individually.
| Modifier | Effect |
private | Restricts access to the declaring class only |
final | Prevents reassignment after initialization |
static | Binds the field to the class, not to any instance |
When final and static appear together, the field becomes a compile-time or class-load-time constant. When final appears without static, the field is an immutable property of each object.
Side-by-Side Comparison
MAX_RETRIES exists once in the JVM. Every Connection object reads the same value. host is created fresh for every new Connection(...) call and holds whatever string was passed to the constructor.
Initialization Rules
The initialization timing is different and matters for correctness.
A static final field that is not assigned by the end of the static initializer block causes a compilation error. A final instance field that is not assigned by the end of every constructor also causes a compilation error. The compiler enforces both guarantees.
Memory and Lifecycle
| Aspect | private static final | private final |
| Storage | One copy in the class's metadata area (metaspace in modern JVMs) | One copy per object on the heap |
| Created when | The class is loaded by the classloader | The object is constructed with new |
| Garbage collected when | The classloader is garbage collected (rarely, for application classes) | The object is garbage collected |
| Memory cost for N instances | Constant regardless of N | Proportional to N |
If you declare a value as private final when it could be private static final, you allocate that value inside every object. For a simple int that wastes 4 bytes per instance, which is negligible. For a String or a large array, the waste multiplies quickly in applications that create millions of instances.
When to Use Each
Use private static final for True Constants
Values that are the same for every instance and do not depend on constructor arguments belong at the class level.
By convention, Java constants use UPPER_SNAKE_CASE names. This naming convention only applies to static final fields, not to instance-level final fields.
Use private final for Per-Instance Immutable State
Values that are fixed after construction but vary between objects belong at the instance level.
Each Order has its own orderId and total. Making these fields final signals that they will not change after construction, which simplifies reasoning about the object's state.
Decision Flowchart
- Is the value the same for every instance of the class? If yes, use
static final. - Does the value depend on constructor arguments or construction-time state? If yes, use
final(nostatic). - If you are unsure, ask whether creating two instances with different values for this field ever makes sense. If the answer is no, it is a class-level constant.
Behavior with Reference Types
final prevents reassignment of the reference, not mutation of the referenced object. This applies to both static final and instance final.
If you need the contents to be truly immutable, wrap the collection.
List.of() (Java 9+) returns an unmodifiable list. Calling add() on it throws UnsupportedOperationException.
Thread Safety Implications
static final fields initialized at declaration or in a static initializer are guaranteed by the JVM to be safely published to all threads. The class loading mechanism ensures this.
final instance fields are also safely published to other threads as long as the object reference does not escape during construction (the "safe publication" guarantee defined in the Java Memory Model, JSR-133). If you leak this in a constructor, another thread could see an uninitialized final field.
Avoid publishing this before the constructor completes. This is a subtle but well-documented pitfall.
Common Pitfalls
- Declaring a shared constant as
private finalinstead ofprivate static final. Every object carries its own identical copy, wasting memory and obscuring the intent that this value is universal. - Assuming
finalmakes an object immutable.finalprevents reassignment of the reference. The object's internal state can still be mutated unless the type itself is immutable. - Using
UPPER_SNAKE_CASEfor instance-levelfinalfields. The naming convention is reserved forstatic finalconstants. Instance fields should usecamelCaseeven when they arefinal. - Leaking
thisin a constructor before allfinalfields are assigned. This breaks the safe publication guarantee and can cause other threads to see default (zero/null) values. - Forgetting that
static finalfields of non-primitive, non-String types are not compile-time constants. Onlystatic finalfields of primitive types orStringinitialized with a literal are true compile-time constants inlined byjavac. Other types are initialized at class load time.
Summary
private static finaldeclares a class-level constant: one copy, shared by all instances, initialized when the class loads.private finaldeclares an instance-level immutable field: one copy per object, initialized in the constructor.- Use
static finalwhen the value is the same for every instance. Usefinalalone when the value varies per object but should not change after construction. finalprevents reassignment of the reference, not mutation of the referenced object. Use unmodifiable collections or immutable types when full immutability is required.- Both kinds of
finalfields carry thread-safety guarantees from the Java Memory Model, but those guarantees depend on not leakingthisduring construction.
Related reading
- problem path for truststore inside docker with spring boot and kafka
- Problems using Maven and SSL behind proxy
- Problems with DCT and IDCT algorithm in java
- Process finished with exit code 1 Spring Boot Intellij
- Profile specific custom property files in Spring boot
- Programmatical approach in Java for file comparison
- Programmatically determine which Java thread holds a lock
- Programmatically shut down Spring Boot application

OOD Fundamentals
Master object-oriented design from first principles, SOLID, design patterns, and classic interview problems with hands-on coding.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
Interview Questions practice on Codemia
Over 8,000 real interview questions from top companies, searchable by company and role.