static
Purpose: Allows access to a field or method without creating an object of the class. Belongs to the class itself, not to a specific instance.
Usage:
- Static constants (
static final) - Utility methods (
Math.max,Collections.sort) - Counters and factory methods
Example:
class Counter {
static int count = 0; // shared for all objects
public Counter() { count++; }
}
Counter c1 = new Counter();
Counter c2 = new Counter();
System.out.println(Counter.count); // 2💡 Features:
staticvariables are created once when the class is loaded.- You cannot access
thisorsuperin astaticmethod. - Often used for singleton and utility classes.
final
Purpose: Fixes a value or prevents modification.
Usage:
- Variable → cannot be redefined.
- Method → cannot be overridden in subclasses.
- Class → cannot be inherited.
Examples:
final int MAX = 10; // constant
// MAX = 15; // error
final class Utils {} // cannot be inherited
class Parent {
final void greet() { System.out.println("Hi"); }
}
class Child extends Parent {
// void greet() {} // error — final method
}💡 Tip:
final is often combined with static → public static final = constant (e.g., Math.PI).
this
Purpose: Reference to the current object — used within methods or constructors.
Example:
class Person {
private String name;
public Person(String name) {
this.name = name; // "this" distinguishes the field from the parameter
}
public void print() {
System.out.println(this.name);
}
}💡 Features:
this()can be used to call another constructor in the same class:
public Person() {
this("Default");
}- You cannot use
thisinstaticmethods (because there is no instance).
super
Purpose: Used to refer to methods and constructors of the parent class.
Example:
class Animal {
void speak() { System.out.println("Animal speaks"); }
}
class Dog extends Animal {
void speak() {
super.speak(); // calls the parent's method
System.out.println("Dog barks");
}
}💡 Features:
super()must be the first line in a constructor.- Helps with overriding methods and initializing subclasses.
volatile
Purpose: Used for variables accessible from multiple threads. Ensures that all threads read the current value from memory, not from the CPU cache.
Example:
class FlagExample {
private volatile boolean running = true;
void stop() {
running = false;
}
void run() {
while (running) {
// executes while running is not changed
}
}
}💡 Without volatile, another thread may not see the changes to the variable,
because it may be cached in the CPU.
📍 Use volatile if the variable does not depend on the previous state (e.g., a boolean flag).
transient
Purpose: Indicates that a field does not need to be serialized. When saving an object (e.g., to a file or network), this field will be skipped.
Example:
class User implements Serializable {
private String username;
private transient String password; // will not be serialized
}💡 The transient field becomes null or 0 after deserialization.
📍 Used when working with Serializable and security (passwords, keys).
Difference between == and .equals()
| Comparison | What it does | Where it is used |
|---|---|---|
== | Compares references (memory addresses) | Objects, primitives |
.equals() | Compares content | Overridden in classes (String, Integer, etc.) |
| Example: |
String a = new String("hello");
String b = new String("hello");
System.out.println(a == b); // false (different objects)
System.out.println(a.equals(b)); // true (same content)💡 For primitives, == compares values, for objects — references.
📍 Tip:
- For strings, collections, and objects — always use
.equals(). - Always override
equals()together withhashCode().
String, StringBuilder, StringBuffer
String
- Immutable object.
- Each concatenation creates a new object in memory.
String s = "Hello";
s += " World"; // a new object is created📍 Used when the string does not change frequently.
⚠️ Avoid concatenating String in a loop — it creates a lot of garbage for GC.
StringBuilder
- Mutable.
- Not synchronized → faster, but not thread-safe.
StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");
System.out.println(sb); // Hello World📍 Used in single-threaded operations.
StringBuffer
- Almost the same as
StringBuilder, but synchronized (thread-safe). - Slightly slower.
StringBuffer sb = new StringBuffer("Hi");
sb.append(" there");
System.out.println(sb);📍 Used in multi-threaded environments when strings are edited concurrently from different threads.
🧩 Comparison
| Class | Mutability | Thread-safety | Speed | When to use |
|---|---|---|---|---|
String | ❌ immutable | ✅ safe | 🐢 slow with frequent changes | Static texts, keys |
StringBuilder | ✅ mutable | ❌ no | ⚡ fast | String generation, templates, loops |
StringBuffer | ✅ mutable | ✅ yes | ⚖️ medium | In multi-threaded environments |
⚙️ Best practices
- ✅ Use
StringBuilderfor concatenation in loops. - ✅ Never compare strings using
==, only.equals(). - ✅ Make constants using
public static final. - ✅ Apply
volatileonly when necessary for synchronization. - ✅ Remember:
transientprotects data during serialization. - ✅ Do not overuse
static— it reduces testability.