Introduction
The final keyword makes a field constant - its value cannot be changed after initialization.
Syntax
final dataType fieldName = value;
Basic Example
class Circle {
final double PI = 3.14159; // Final field
double radius;
double getArea() {
return PI * radius * radius;
}
void changePI() {
// PI = 3.14; // ❌ Error: cannot change final field
}
}
public class Main {
public static void main(String[] args) {
Circle c = new Circle();
c.radius = 5;
System.out.println("Area: " + c.getArea());
// c.PI = 3.14; // ❌ Error: cannot change final field
}
}
Initialization of Final Fields
1. At Declaration:
class Constants {
final int MAX_SIZE = 100;
final String APP_NAME = "MyApp";
final double TAX_RATE = 0.18;
}
2. In Constructor:
class Student {
final int rollNo; // Not initialized here
String name;
Student(int rollNo, String name) {
this.rollNo = rollNo; // Initialize in constructor
this.name = name;
}
void display() {
System.out.println("Roll No: " + rollNo);
System.out.println("Name: " + name);
}
}
public class Main {
public static void main(String[] args) {
Student s = new Student(101, "John");
s.display();
s.name = "Alice"; // ✓ OK: name is not final
// s.rollNo = 102; // ❌ Error: rollNo is final
}
}
3. In Initialization Block:
class Example {
final int value;
// Initialization block
{
value = 100;
}
}
Final Fields Must Be Initialized
class Wrong {
final int x; // ❌ Error: final field not initialized
}
class Correct1 {
final int x = 10; // ✓ OK: initialized at declaration
}
class Correct2 {
final int x;
Correct2() {
x = 10; // ✓ OK: initialized in constructor
}
}
Constants with Final
class MathConstants {
final double PI = 3.14159;
final double E = 2.71828;
final int MAX_VALUE = Integer.MAX_VALUE;
}
class Config {
final String DATABASE_URL = "localhost:3306";
final int MAX_CONNECTIONS = 100;
final int TIMEOUT = 30;
}
Final with Static
Static final = Class-level constant (most common for constants).
class Circle {
static final double PI = 3.14159; // Class constant
double radius;
double getArea() {
return PI * radius * radius;
}
}
public class Main {
public static void main(String[] args) {
// Access without creating object
System.out.println("PI = " + Circle.PI);
Circle c1 = new Circle();
Circle c2 = new Circle();
// Both share same PI value
}
}
Complete Example
class BankAccount {
final String accountNumber; // Final field
final String accountType; // Final field
private double balance; // Can change
// Initialize final fields in constructor
BankAccount(String accountNumber, String accountType) {
this.accountNumber = accountNumber;
this.accountType = accountType;
this.balance = 0.0;
}
void deposit(double amount) {
balance += amount;
}
void display() {
System.out.println("Account: " + accountNumber);
System.out.println("Type: " + accountType);
System.out.println("Balance: " + balance);
}
}
public class Main {
public static void main(String[] args) {
BankAccount acc = new BankAccount("1234567890", "Savings");
acc.deposit(1000);
acc.display();
// acc.accountNumber = "9999"; // ❌ Error: final field
// acc.accountType = "Current"; // ❌ Error: final field
acc.deposit(500); // ✓ OK: balance can change
}
}
Naming Convention
Constants (static final fields) are typically named in UPPER_CASE.
class Constants {
static final int MAX_SIZE = 100;
static final String APP_NAME = "MyApp";
static final double PI = 3.14159;
static final int MIN_AGE = 18;
}
Final vs Non-Final
class Example {
final int CONSTANT = 100; // Cannot change
int variable = 200; // Can change
void test() {
// CONSTANT = 150; // ❌ Error
variable = 250; // ✓ OK
}
}
Practical Use Cases
1. Configuration Values:
class AppConfig {
static final String VERSION = "1.0.0";
static final int MAX_USERS = 1000;
static final String API_URL = "https://api.example.com";
}
2. Unique Identifiers:
class Employee {
final int empId; // Cannot change once assigned
String name; // Can be updated
Employee(int empId, String name) {
this.empId = empId;
this.name = name;
}
}
3. Mathematical Constants:
class Physics {
static final double SPEED_OF_LIGHT = 299792458; // m/s
static final double GRAVITY = 9.8; // m/s²
}
Benefits of Final Fields
- Immutability: Values cannot be changed
- Thread Safety: Safe to share across threads
- Compiler Optimization: Better performance
- Intent: Shows value should not change
- Error Prevention: Prevents accidental modification
Comparison Table
| Type | Keyword | Scope | Can Change? |
|---|---|---|---|
| Instance constant | final | Per object | No |
| Class constant | static final | Per class | No |
| Instance variable | (none) | Per object | Yes |
| Class variable | static | Per class | Yes |
Quick Reference
class Example {
// Class constant (most common)
static final int MAX = 100;
// Instance constant
final String id;
// Regular field
int count;
Example(String id) {
this.id = id; // Initialize final field
}
}
// Usage
System.out.println(Example.MAX); // Access class constant
Example obj = new Example("A001");
// obj.id = "B002"; // ❌ Error: final
obj.count = 10; // ✓ OK: not final
Exam Tips
Remember:
- final fields = constant, cannot change
- Must initialize once
- Initialize at: declaration, constructor, or initialization block
- static final = class constant (common pattern)
- Constants named in UPPER_CASE
- Provides immutability
- Cannot reassign after initialization
- Good for IDs, config values, constants
Common Questions:
- What is final keyword?
- Can final fields be changed?
- Where to initialize final fields?
- Difference between final and non-final?
- What is static final?
- Naming convention for constants?
- Benefits of final fields?