Special Keywords and Modifiers
A complete guide to Java's special keywords and modifiers: static, final, abstract, synchronized, volatile, transient, native, strictfp, instanceof, and a deeper look at this and super.
What are Keywords and Modifiers?
Java reserves a set of words that carry specific meaning to the compiler and the runtime. You cannot use them as identifiers for variables, methods, or classes. Among these, modifiers are keywords that change the behaviour or accessibility of a declaration. Some modifiers affect visibility, such as public and private. Others affect how something is stored, shared, or executed.
This tutorial focuses on the modifiers and special keywords that show up most in real Java code and that beginners often find confusing: static, final, abstract, synchronized, volatile, transient, native, strictfp, instanceof, and a revisit of this and super.
Where modifiers appear
Most modifiers can appear on more than one kind of declaration, but their meaning shifts depending on context.
- On a class:static (nested classes), final, abstract, strictfp.
- On a field:static, final, volatile, transient.
- On a method:static, final, abstract, synchronized, native, strictfp.
- On a local variable:final only.
static
The static modifier means that something belongs to the class itself rather than to any particular instance of that class. A static field is shared across all objects: there is only one copy of it in memory, and every object reads and writes the same value. A static method can be called using the class name directly, without creating an object first.
Static methods cannot access instance members (non-static fields or methods) directly, because there is no this reference inside them. They can only work with other static members or with objects passed to them as arguments. Static blocks are special initialisation blocks that run once when the class is first loaded by the JVM.
Three places where static appears
Understanding each use case separately makes the keyword much less confusing.
- Static field:One copy shared by all instances. Useful for counters, constants, or shared configuration.
- Static method:Called on the class, not on an object. Useful for utility functions (Math.sqrt(), Arrays.sort()) and factory methods.
- Static block:Runs once when the class is loaded. Useful for complex initialisation of static fields that cannot be done in a single expression.
static Fields, Methods, and Blocks
JavaA Counter class demonstrating a shared field, a utility method, and a static initialiser block.
final
The final keyword means "this cannot change or be extended further." Its precise effect depends on where you place it. On a variable, it means the variable can only be assigned once; on a method, it means no subclass can override it; on a class, it means no class can extend it.
For object references declared final, the reference itself is fixed, but the object it points to is still mutable. This is a subtle but important distinction. If you write final List<String> names = new ArrayList<>(), you cannot make names point to a different list, but you can still call names.add() to modify the existing list.
final Variables, Methods, and Classes
JavaDemonstrating all three uses of final in context.
abstract
The abstract modifier signals that something is incomplete by design and must be completed elsewhere. An abstract class cannot be instantiated directly: it exists to be extended. An abstract method has no body: the concrete subclass must provide the implementation. If a class contains even one abstract method, the class itself must also be declared abstract.
Abstraction is covered in depth in the Abstraction tutorial. Here, the focus is on understanding abstract as a keyword modifier and how it interacts with final and static.
Illegal modifier combinations with abstract
Some combinations of modifiers are logically contradictory and cause compile errors.
- abstract + final:Contradictory. final says the class cannot be extended; abstract says it must be extended to be useful.
- abstract + static:Not allowed on methods. A static method belongs to the class and cannot be overridden, which defeats the purpose of being abstract.
- abstract + private:Not allowed on methods. A private method is not visible to subclasses, so a subclass could never override it to provide the required implementation.
abstract in Context
JavaAn abstract Vehicle class with both abstract and concrete methods, extended by two subclasses.
synchronized
When multiple threads access the same object at the same time, you can get race conditions: two threads both read a value, both modify it, and one thread's change overwrites the other's. The synchronized keyword prevents this by allowing only one thread to execute a given block of code on a given object at a time. A thread must acquire the object's intrinsic lock (also called a monitor) before entering, and releases it when it exits.
You can synchronise an entire method by adding the keyword to the method signature, or synchronise just a critical block of code using a synchronized(obj) block. Synchronising a smaller block is often preferable because it reduces the time the lock is held, allowing other threads to proceed sooner.
Key facts about synchronized
synchronized is the simplest built-in thread-safety mechanism, but it comes with trade-offs.
- On an instance method: the lock is the instance itself (this). Only one thread can execute any synchronized instance method of the same object at a time.
- On a static method: the lock is the Class object. Only one thread can execute any synchronized static method of that class at a time.
- On a block: you choose which object to lock on, giving you finer control over granularity.
- Synchronization prevents race conditions but can introduce performance bottlenecks if overused. For high-throughput code, consider the java.util.concurrent package instead.
synchronized Methods and Blocks
JavaA shared bank account accessed by two threads, demonstrating why synchronisation is necessary.
volatile
Modern CPUs and JVMs optimise performance by caching variable values in thread-local registers or CPU caches. This means one thread might see a stale copy of a value that another thread has already updated in main memory. The volatile keyword tells the JVM never to cache this field locally: every read must come from main memory, and every write must go directly to main memory. This guarantees visibility across threads.
However, volatile does not guarantee atomicity. If two threads both read a volatile int and then both increment it, you can still lose updates because increment is a read-modify-write operation, not a single atomic step. volatile is most useful for simple flag-style variables (like a stop signal) where one thread writes and another thread reads.
volatile for Thread Visibility
JavaUsing a volatile boolean flag to safely signal a worker thread to stop.
transient
Java's serialisation mechanism converts an object into a byte stream that can be saved to a file, sent over a network, or stored in a database, and then reconstructed later. By default, every non-static field of a Serializable class is included in this byte stream.
The transient modifier tells the serialisation engine to skip a particular field. This is useful for fields that hold sensitive data (such as passwords or session tokens), fields that cannot be serialised (such as open database connections or file handles), or derived fields that can be recomputed from other data.
transient Fields and Serialisation
JavaSerialising a User object while skipping the password field marked transient.
native
The native modifier marks a method whose implementation is written in another programming language, typically C or C++, and is accessed through the Java Native Interface (JNI). The method declaration in Java ends with a semicolon and has no body, similar in looks to an abstract method.
The JVM links the native method to a compiled shared library (a .dll on Windows or a .so on Linux). You will encounter native methods in the core Java class library itself: Object.hashCode(), System.currentTimeMillis(), and Thread.sleep() are all implemented natively because they need to talk directly to the operating system. Most application code never needs to write native methods directly.
When native methods are used
Native code exists to bridge Java and the underlying platform where Java alone cannot reach.
- Accessing hardware directly, such as reading from a GPU, a serial port, or a sensor.
- Calling existing C/C++ libraries without rewriting them in Java.
- Performing operations that require OS-level calls not exposed through the Java API.
- Optimising extremely performance-critical routines that the JIT compiler cannot optimise well enough.
native Method Declaration
JavaShowing how a native method is declared in Java. The actual implementation would be in a C file loaded at runtime.
strictfp
Floating-point arithmetic on different hardware platforms and JVM implementations can produce slightly different results because CPUs use varying internal precision for intermediate calculations. The strictfp modifier forces all floating-point operations within an annotated class or method to follow the IEEE 754 standard exactly. This produces identical results on any platform, at the potential cost of a small performance hit.
From Java 17 onwards, strictfp is the default behaviour for all code, meaning the modifier is now effectively redundant. It is still a legal keyword and will not cause a compile error, but modern code rarely uses it. You will encounter it mainly when reading older codebases or working with systems that ran on pre-Java 17 runtimes.
strictfp in Practice
JavaA class marked strictfp ensures reproducible floating-point arithmetic across platforms.
instanceof
The instanceof operator tests whether an object is an instance of a particular class or interface. It returns true if the object on the left can be safely cast to the type on the right, and false otherwise. If the left operand is null, the result is always false.
Java 16 introduced pattern matching for instanceof, allowing you to combine the type check and the cast into one step. Instead of checking the type and then casting on separate lines, you can write if (obj instanceof String s), which both checks the type and declares a new variable s that is already of type String and in scope within the if block.
instanceof: Classic and Pattern Matching
JavaContrasting the old-style instanceof check and cast with Java 16+ pattern matching.
this and super Revisited
You have already encountered this and super in earlier tutorials. Here, the goal is to consolidate all their uses in one place and highlight the nuances that often trip people up.
All uses of this
this always refers to the current object. It has three distinct uses.
- this.field or this.method():Disambiguates between an instance field and a local variable or parameter that share the same name. Common in constructors and setters.
- this(...):Constructor chaining. Calls another constructor in the same class. Must be the very first statement in the constructor body. Used to avoid duplicate initialisation code.
- return this:Returns the current object from a method, enabling method chaining (the builder pattern and fluent APIs).
All uses of super
super always refers to the immediate parent class. It also has three distinct uses.
- super.field:Accesses a field in the parent class that is hidden by a field with the same name in the subclass. Rare in practice.
- super.method():Calls an overridden method in the parent class. Useful when you want to extend, not completely replace, the parent's behaviour.
- super(...):Calls a parent class constructor. Must be the very first statement in the subclass constructor. If omitted and the parent has a no-arg constructor, Java inserts super() automatically.
this and super: All Uses in One Example
JavaA fluent builder-style class combined with inheritance to show every use of this and super.
Quick Reference
Below is a concise summary of every keyword covered in this tutorial. Use it as a reference when you encounter these modifiers in code you are reading or debugging.
Keyword summary
Eight modifiers and two special keywords, each with a one-line purpose.
- static:Belongs to the class, not to instances. Shared across all objects.
- final:Cannot be reassigned (variable), overridden (method), or extended (class).
- abstract:Incomplete by design. The class cannot be instantiated; the method has no body and must be overridden.
- synchronized:Only one thread can execute this method or block on the same object at a time.
- volatile:Every read/write goes directly to main memory. Guarantees visibility, not atomicity.
- transient:Skip this field during serialisation. Useful for sensitive or non-serialisable data.
- native:The method is implemented in another language (C/C++) and linked via JNI.
- strictfp:Force IEEE 754 compliant floating-point arithmetic. Redundant from Java 17 onwards.
- instanceof:Tests whether an object is an instance of a given type. Returns false for null.
- this / super:this: current object reference or same-class constructor call. super: parent class member access or parent constructor call.
Quiz - Test Your Knowledge
Ten questions covering static, final, abstract, synchronized, volatile, transient, native, strictfp, instanceof, and the uses of this and super. Read each option carefully before selecting your answer.
Knowledge Check
1. Which of the following is a valid use of the static keyword in Java?
2. What happens when you declare a local variable as final in Java?
3. What does the synchronized keyword guarantee when applied to a method?
4. Why would you declare a field volatile in Java?
5. Which keyword marks a field so that it is skipped during Java object serialisation?
6. What is the primary purpose of the native keyword?
7. What does strictfp ensure when applied to a class or method?
8. Which statement about the instanceof operator is correct?
9. Inside a constructor, what does this(...) do?
10. When is it mandatory to use super() explicitly in a subclass constructor?