final KeywordComplete Revision Guide — Class · Method · Variable — Hinglish mein
final ka matlab hai — "Ye cheez ab CHANGE NAHI HOGI!"
Real life analogies: Constitution ka Article → final (easily change nahi hota) | Diamond → final hardness | Death → final (irreversible!)
1. SECURITY: Koi class inherit karke original behaviour change nahi kar sakti.
2. IMMUTABILITY: String class final hai — koi String inherit karke internal behavior nahi badal sakta.
3. OPTIMIZATION: JVM final class ke methods ko directly call kar sakta hai (no virtual dispatch needed).
Real Examples: java.lang.String, java.lang.Integer, java.lang.Math — ye sab FINAL hain!
public class FinalClass1 { // final class - koi extend nahi kar sakta! static final class Singleton { private static Singleton instance = null; private String data; private Singleton() { this.data = "Singleton Data"; System.out.println("Singleton instance created!"); } static Singleton getInstance() { if (instance == null) { instance = new Singleton(); } return instance; } String getData() { return data; } void setData(String data) { this.data = data; } } // class HackedSingleton extends Singleton { } ← ERROR! static class NormalClass { String name = "Normal"; void show() { System.out.println("NormalClass: " + name); } } static class ExtendedNormal extends NormalClass { void show() { System.out.println("ExtendedNormal!"); } } public static void main(String[] args) { Singleton s1 = Singleton.getInstance(); Singleton s2 = Singleton.getInstance(); System.out.println("s1 data: " + s1.getData()); System.out.println("Same instance? " + (s1 == s2)); s1.setData("Updated Data"); System.out.println("s2 data: " + s2.getData()); } }
Singleton instance created! s1 data: Singleton Data Same instance? true s2 data: Updated Data
final class Singleton ko koi extend nahi kar sakta. getInstance() method sirf ek hi object banata hai — yahi Singleton pattern hai. NormalClass extend ho sakti hai kyunki wo final nahi — compare karo!
public class FinalClass2 { static final class SecureConfig { // Variables automatically final NAHI hote! String host = "localhost"; // change ho sakta hai ✅ int port = 8080; // change ho sakta hai ✅ final String PROTOCOL = "HTTPS"; // explicitly final // Yeh method automatically final hai! // (kyunki class final hai) void displayConfig() { System.out.println("Host: " + host); System.out.println("Port: " + port); System.out.println("Protocol: " + PROTOCOL); } void updatePort(int newPort) { this.port = newPort; // ✅ variable change ho sakta hai! System.out.println("Port updated to: " + newPort); } // PROTOCOL = "HTTP"; ← ERROR! final variable change nahi hoga } public static void main(String[] args) { SecureConfig config = new SecureConfig(); config.displayConfig(); config.host = "production-server.com"; // ✅ allowed! config.updatePort(443); config.displayConfig(); } }
Host: localhost Port: 8080 Protocol: HTTPS Port updated to: 443 Host: production-server.com Port: 443 Protocol: HTTPS
final class ke andar PROTOCOL explicitly final hai — change nahi hoga. But host aur port final nahi — change ho sakte hain. Methods auto-final hote hain, variables nahi!
public class FinalClass3 { static final class ImmutablePoint { // Both variables final → truly immutable! private final double x; private final double y; ImmutablePoint(double x, double y) { this.x = x; this.y = y; } double getX() { return x; } double getY() { return y; } // Returns NEW object instead of modifying! ImmutablePoint translate(double dx, double dy) { return new ImmutablePoint(x + dx, y + dy); } ImmutablePoint scale(double factor) { return new ImmutablePoint(x * factor, y * factor); } double distanceTo(ImmutablePoint other) { double dx = this.x - other.x; double dy = this.y - other.y; return Math.sqrt(dx*dx + dy*dy); } public String toString() { return "(" + x + ", " + y + ")"; } } public static void main(String[] args) { ImmutablePoint p1 = new ImmutablePoint(3.0, 4.0); System.out.println("p1 = " + p1); ImmutablePoint p2 = p1.translate(1.0, 1.0); ImmutablePoint p3 = p1.scale(2.0); System.out.println("p2 (translated) = " + p2); System.out.println("p3 (scaled) = " + p3); System.out.println("p1 unchanged = " + p1); // p1.x = 10.0; ← ERROR! final variable! } }
p1 = (3.0, 4.0) p2 (translated) = (4.0, 5.0) p3 (scaled) = (6.0, 8.0) p1 unchanged = (3.0, 4.0)
ImmutablePoint ek perfect immutable class hai. Operations (translate, scale) naya object return karte hain — original p1 kabhi change nahi hota. final class + final variables = complete immutability guarantee!
public class FinalClass4 { static final class MathConstants { static final double PI = 3.14159265358979; static final double E = 2.71828182845904; static final double SQRT2 = 1.41421356237309; static final double GOLDEN_RATIO = 1.61803398874989; private MathConstants() { } // Prevent instantiation static double circleArea(double r) { return PI * r * r; } static double circlePerimeter(double r) { return 2 * PI * r; } } static final class AppSettings { String theme = "Dark"; boolean notifications = true; int fontSize = 14; static final String APP_VERSION = "2.1.0"; static final int MAX_USERS = 1000; void display() { System.out.println("Version: " + APP_VERSION); System.out.println("Theme: " + theme); System.out.println("Font: " + fontSize); } } public static void main(String[] args) { System.out.printf("Circle area (r=5): %.2f%n", MathConstants.circleArea(5)); AppSettings settings = new AppSettings(); settings.display(); settings.theme = "Light"; // ✅ not final! settings.fontSize = 16; settings.display(); // AppSettings.MAX_USERS = 2000; ← ERROR! final! } }
Circle area (r=5): 78.54 Version: 2.1.0 Theme: Dark Font: 14 Version: 2.1.0 Theme: Light Font: 16
MathConstants mein sirf static final constants hain — change nahi ho sakte, instantiation bhi nahi. AppSettings mein APP_VERSION aur MAX_USERS final constants hain, but theme aur fontSize change ho sakte hain. Final class ≠ final variables!
1. SECURITY: Critical logic protect karo — authentication, security checks override nahi ho sakti.
2. TEMPLATE PATTERN: Base class algorithm ka structure fix karo, steps vary ho sakte hain.
3. PERFORMANCE: JVM inline kar sakta hai final methods.
Key Rule: final method ko CALL kar sakte hain — sirf OVERRIDE nahi kar sakte!
public class FinalMethod1 { static class BankAccount { String accountNo, owner; double balance; BankAccount(String accNo, String owner, double balance) { this.accountNo = accNo; this.owner = owner; this.balance = balance; } // FINAL method - security critical! // Koi override karke fraud nahi kar sakta! final boolean authenticate(String pin) { boolean valid = pin.equals("1234"); System.out.println("[AUTH] " + owner + ": " + (valid ? "GRANTED" : "DENIED")); return valid; } // FINAL method - financial logic protected final void transfer(BankAccount target, double amount) { if (balance >= amount) { this.balance -= amount; target.balance += amount; System.out.println("[TRANSFER] Rs." + amount + " from " + owner + " to " + target.owner); } else { System.out.println("[TRANSFER] FAILED - Insufficient balance"); } } // Non-final - child can customize void displayBalance() { System.out.println(owner + ": Rs." + balance); } } static class PremiumAccount extends BankAccount { double cashbackRate; PremiumAccount(String accNo, String owner, double balance, double cashbackRate) { super(accNo, owner, balance); this.cashbackRate = cashbackRate; } // authenticate() override karna: ← ERROR! final // Non-final method override ✅ void displayBalance() { System.out.println("[PREMIUM] " + owner + ": Rs." + balance + " | Cashback: " + cashbackRate + "%"); } } public static void main(String[] args) { BankAccount regular = new BankAccount("R01", "Rahul", 50000); PremiumAccount premium = new PremiumAccount("P01", "Priya", 100000, 2.0); regular.authenticate("1234"); regular.authenticate("9999"); regular.transfer(premium, 10000); regular.displayBalance(); // BankAccount version premium.displayBalance(); // PremiumAccount version } }
[AUTH] Rahul: GRANTED [AUTH] Rahul: DENIED [TRANSFER] Rs.10000.0 from Rahul to Priya Rahul: Rs.40000.0 [PREMIUM] Priya: Rs.110000.0 | Cashback: 2.0%
authenticate() aur transfer() final hain — koi override karke fraud nahi kar sakta! displayBalance() non-final hai — PremiumAccount ne apna custom display override kiya. Security methods final, display method flexible!
public class FinalMethod2 { static abstract class DataProcessor { // TEMPLATE METHOD - final! // Algorithm structure fixed, steps can vary final void process() { System.out.println("--- Processing Start ---"); readData(); // Step 1 - can override validateData(); // Step 2 - can override processData(); // Step 3 - must override (abstract) saveResults(); // Step 4 - can override System.out.println("--- Processing End ---"); } void readData() { System.out.println("[DEFAULT] Reading data..."); } void validateData() { System.out.println("[DEFAULT] Validating..."); } abstract void processData(); // must override void saveResults() { System.out.println("[DEFAULT] Saving results..."); } } static class CSVProcessor extends DataProcessor { String filename; CSVProcessor(String f) { this.filename = f; } void readData() { System.out.println("[CSV] Reading: " + filename); } void validateData() { System.out.println("[CSV] Checking columns..."); } void processData() { System.out.println("[CSV] Parsing CSV rows..."); } void saveResults() { System.out.println("[CSV] Saving to database..."); } // process() override karna ← ERROR! final! } static class JSONProcessor extends DataProcessor { String apiUrl; JSONProcessor(String url) { this.apiUrl = url; } void readData() { System.out.println("[JSON] Fetching: " + apiUrl); } void processData() { System.out.println("[JSON] Parsing JSON..."); } // validateData() aur saveResults() default use karenge } public static void main(String[] args) { DataProcessor csv = new CSVProcessor("users.csv"); DataProcessor json = new JSONProcessor("https://api.example.com/data"); csv.process(); // final method - same structure! json.process(); // final method - same structure! } }
--- Processing Start --- [CSV] Reading: users.csv [CSV] Checking columns... [CSV] Parsing CSV rows... [CSV] Saving to database... --- Processing End --- --- Processing Start --- [JSON] Fetching: https://api.example.com/data [DEFAULT] Validating... [JSON] Parsing JSON... [DEFAULT] Saving results... --- Processing End ---
process() final hai — algorithm ka structure fixed hai. Steps (readData, validateData etc.) override ho sakte hain — har processor apna kaam karta hai. Structure same raha, implementation vary ki. Yahi Template Method Pattern hai!
public class FinalMethod3 { static class A { void normalMethod() { System.out.println("A: normalMethod"); } final void finalMethod() { System.out.println("A: finalMethod (FINAL)"); } } static class B extends A { void normalMethod() { // ✅ Can override non-final System.out.println("B: normalMethod (overridden)"); } // final void finalMethod() { } ← ERROR! Cannot override void bMethod() { System.out.println("B: bMethod"); finalMethod(); // CAN CALL final method — just can't OVERRIDE! } } static class C extends B { void normalMethod() { // Can still override System.out.println("C: normalMethod (overridden again)"); super.normalMethod(); // B's version } // finalMethod still cannot override } public static void main(String[] args) { A objA = new A(); B objB = new B(); C objC = new C(); System.out.println("--- normalMethod ---"); objA.normalMethod(); // A's version objB.normalMethod(); // B's version objC.normalMethod(); // C's version (calls B's via super) System.out.println("--- finalMethod ---"); objA.finalMethod(); // A's version objB.finalMethod(); // STILL A's version! objC.finalMethod(); // STILL A's version! objB.bMethod(); // calls finalMethod inside } }
--- normalMethod --- A: normalMethod B: normalMethod (overridden) C: normalMethod (overridden again) B: normalMethod (overridden) --- finalMethod --- A: finalMethod (FINAL) A: finalMethod (FINAL) A: finalMethod (FINAL) B: bMethod A: finalMethod (FINAL)
finalMethod() A, B, C teeno se call karo — hamesha A ka version chalega! Override karna impossible. normalMethod() har level pe override ho sakti hai. CALL karna aur OVERRIDE karna — yeh do alag cheezein hain!
public class FinalMethod4 { static class User { String username; String role; boolean isLoggedIn; User(String username, String role) { this.username = username; this.role = role; this.isLoggedIn = false; } // FINAL - security method - cannot tamper! final boolean hasPermission(String action) { if (!isLoggedIn) { System.out.println("[SECURITY] Not logged in!"); return false; } boolean allowed = false; switch (action) { case "READ": allowed = true; break; case "WRITE": allowed = role.equals("ADMIN") || role.equals("EDITOR"); break; case "DELETE": allowed = role.equals("ADMIN"); break; } System.out.println("[SECURITY] " + username + " " + action + ": " + (allowed ? "ALLOWED" : "DENIED")); return allowed; } // FINAL login - cannot modify logic final void login(String password) { if ("password123".equals(password)) { isLoggedIn = true; System.out.println(username + " logged in!"); } else { System.out.println("Wrong password!"); } } } static class AdminUser extends User { AdminUser(String username) { super(username, "ADMIN"); } // hasPermission() aur login() override NAHI kar sakte! // Isliye security bypass impossible! } public static void main(String[] args) { User regularUser = new User("Rahul", "VIEWER"); AdminUser admin = new AdminUser("SuperAdmin"); regularUser.hasPermission("READ"); // not logged in regularUser.login("password123"); admin.login("password123"); regularUser.hasPermission("READ"); regularUser.hasPermission("DELETE"); admin.hasPermission("DELETE"); } }
[SECURITY] Not logged in! Rahul logged in! SuperAdmin logged in! [SECURITY] Rahul READ: ALLOWED [SECURITY] Rahul DELETE: DENIED [SECURITY] SuperAdmin DELETE: ALLOWED
hasPermission() aur login() final hain — AdminUser in methods ko override karke apni permissions hack nahi kar sakta. Real-world security systems mein yahi pattern use hota hai. Final = Tamper-proof!
1. INSTANCE final: Declare ya constructor mein initialize karo — object specific constant.
2. STATIC final: Class level constant — naming convention: ALL_CAPS_UNDERSCORE
3. LOCAL final: Method ke andar — sirf final modifier allowed, static/private nahi!
Important: final reference type mein — reference change nahi hota, but object ke andar values change ho sakti hain!
public class FinalVariable1 { static class Circle { // static final - CLASS CONSTANT (all caps!) static final double PI = 3.14159; static final String SHAPE_TYPE = "Circle"; // instance final - object specific constant final double radius; // constructor mein set hoga final String color; // constructor mein set hoga final int id; static int idCounter = 0; Circle(double radius, String color) { idCounter++; this.id = idCounter; // final set in constructor! this.radius = radius; this.color = color; } double getArea() { return PI * radius * radius; } double getPerimeter() { return 2 * PI * radius; } void display() { System.out.println("Circle #" + id + " | r=" + radius + " | color=" + color); System.out.printf(" Area=%.2f, Perim=%.2f%n", getArea(), getPerimeter()); } } public static void main(String[] args) { Circle c1 = new Circle(5.0, "Red"); Circle c2 = new Circle(7.0, "Blue"); c1.display(); c2.display(); System.out.println("PI = " + Circle.PI); // Circle.PI = 3.0; ← ERROR! // c1.radius = 10.0; ← ERROR! } }
Circle #1 | r=5.0 | color=Red Area=78.54, Perim=31.42 Circle #2 | r=7.0 | color=Blue Area=153.94, Perim=43.98 PI = 3.14159
PI static final — class level constant, sabke liye same. radius, color, id instance final — constructor mein set kiye, ab change impossible. Ek baar set karo, hamesha same!
public class FinalVariable2 { static class Config { // WAY 1: Direct initialization final String APP_NAME = "MyApp"; // WAY 2: Initialize in constructor final int MAX_SIZE; final String DB_URL; // WAY 3: Static final with static block static final String VERSION; static final int BUILD_NO; static { VERSION = "2.1.0"; BUILD_NO = 1042; System.out.println("Static finals initialized!"); } Config(int maxSize, String dbUrl) { this.MAX_SIZE = maxSize; // final in constructor! this.DB_URL = dbUrl; } void display() { System.out.println("App: " + APP_NAME + " | Version: " + VERSION); System.out.println("MaxSize: " + MAX_SIZE + " | DB: " + DB_URL); } } public static void main(String[] args) { Config c1 = new Config(100, "mysql://localhost/db1"); Config c2 = new Config(200, "mysql://server/db2"); c1.display(); c2.display(); System.out.println("Static same? " + (c1.APP_NAME.equals(c2.APP_NAME))); System.out.println("Instance diff? c1=" + c1.MAX_SIZE + " c2=" + c2.MAX_SIZE); } }
Static finals initialized! App: MyApp | Version: 2.1.0 MaxSize: 100 | DB: mysql://localhost/db1 App: MyApp | Version: 2.1.0 MaxSize: 200 | DB: mysql://server/db2 Static same? true Instance diff? c1=100 c2=200
VERSION static final — sabke liye same. MAX_SIZE instance final — har object ka alag value, par ek baar set hone ke baad change nahi hoga!
public class FinalVariable3 { static int factorial(int n) { final int INPUT = n; // original value preserve int result = 1; for (int i = 1; i <= INPUT; i++) { result *= i; // INPUT = 5; ← ERROR! local final! } return result; } static void demonstrateLocalFinal() { final int MAX = 100; // static final int X = 5; ← ERROR! static not for local! // private final int Y = 5; ← ERROR! private not for local! // final reference type - object change ho sakta hai! final int[] arr = {1, 2, 3}; arr[0] = 99; // ✅ Array contents change ho sakta! // arr = new int[]{4,5,6}; ← ERROR! reference cannot change! System.out.println("MAX = " + MAX); System.out.println("arr[0] = " + arr[0]); // 99 // Effectively final (Java 8+) int num = 42; // not declared final but never changed Runnable r = () -> System.out.println("num = " + num); r.run(); } static void loopFinal() { // final in loop - each iteration new variable! for (int i = 0; i < 5; i++) { final int loopVal = i * i; // new final each iteration System.out.println("i=" + i + " square=" + loopVal); } } public static void main(String[] args) { System.out.println("5! = " + factorial(5)); demonstrateLocalFinal(); loopFinal(); } }
5! = 120 MAX = 100 arr[0] = 99 num = 42 i=0 square=0 i=1 square=1 i=2 square=4 i=3 square=9 i=4 square=16
final lagta hai — static, private, public nahi! final int[] arr mein arr[0] = 99 allowed — array ka content change kar sakte hain, sirf reference reassign nahi ho sakta! Loop mein har iteration mein naya final variable banta hai.
public class FinalVariable4 { static class Address { String city, state; Address(String c, String s) { city = c; state = s; } public String toString() { return city + ", " + state; } } static class Person { final String name; // String immutable anyway final Address address; // reference final - object can change! final int[] scores; // array reference - contents can change! Person(String name, String city, String state, int[] scores) { this.name = name; this.address = new Address(city, state); this.scores = scores; } void demonstrateFinal() { System.out.println("name = " + name); System.out.println("address = " + address); // address reference final - cannot reassign // BUT address object's fields CAN change! address.city = "Mumbai"; // ✅ ALLOWED! System.out.println("address.city changed: " + address); // address = new Address("Delhi","UP"); ← ERROR! System.out.println("scores[0] = " + scores[0]); scores[0] = 99; // ✅ Content change allowed! System.out.println("scores[0] changed: " + scores[0]); // scores = new int[]{1,2,3}; ← ERROR! } } public static void main(String[] args) { Person p = new Person("Rahul", "Delhi", "UP", new int[]{85, 90, 78}); p.demonstrateFinal(); } }
name = Rahul address = Delhi, UP address.city changed: Mumbai, UP scores[0] = 85 scores[0] changed: 99
final Address address — address = new Address() reassign nahi kar sakte. But address.city = "Mumbai" ALLOWED hai! Reference fixed hai, object mutable hai. Yeh ek bahut important aur confusing distinction hai — exam mein zaroor aata hai!
public class FinalVariable5 { // Constants for application (static final) static final String APP_NAME = "FinalDemo"; static final double VERSION = 1.0; static final int MAX_RETRIES = 3; static final boolean DEBUG_MODE = false; // Enum-like constants static final int STATUS_ACTIVE = 1; static final int STATUS_INACTIVE = 0; static final int STATUS_DELETED = -1; // Instance finals final String sessionId; final long createdAt; int loginCount; // not final - can change FinalVariable5(String sessionId) { this.sessionId = sessionId; this.createdAt = System.currentTimeMillis(); this.loginCount = 0; } void login() { loginCount++; System.out.println("Session: " + sessionId + " | Login #" + loginCount); } static void showConstants() { System.out.println("App: " + APP_NAME + " v" + VERSION); System.out.println("Max Retries: " + MAX_RETRIES); System.out.println("ACTIVE=" + STATUS_ACTIVE + " INACTIVE=" + STATUS_INACTIVE); } public static void main(String[] args) { showConstants(); FinalVariable5 s1 = new FinalVariable5("SESSION_A1B2"); FinalVariable5 s2 = new FinalVariable5("SESSION_C3D4"); s1.login(); s1.login(); s2.login(); System.out.println("s1 sessionId: " + s1.sessionId); System.out.println("s2 sessionId: " + s2.sessionId); System.out.println("s1 logins: " + s1.loginCount); } }
App: FinalDemo v1.0 Max Retries: 3 ACTIVE=1 INACTIVE=0 Session: SESSION_A1B2 | Login #1 Session: SESSION_A1B2 | Login #2 Session: SESSION_C3D4 | Login #1 s1 sessionId: SESSION_A1B2 s2 sessionId: SESSION_C3D4 s1 logins: 2
APP_NAME static final — class constant. sessionId instance final — constructor mein set, badal nahi sakta. loginCount final nahi — easily change hota hai. Final ka use wahan karo jahan value permanently fixed rahni chahiye!
| Type | Kya Hota Hai | Kya Allowed | Kya NOT Allowed |
|---|---|---|---|
| final class | Class sealed ho jaati hai | ✓ Instantiate ✓ Methods call |
✗ Extend/Inherit |
| final method | Method locked ho jaata hai | ✓ Call karo ✓ Other methods override |
✗ Override this method |
| final variable | Value constant ho jaati hai | ✓ Read karo ✓ Object content change (ref type) |
✗ Reassign value ✗ Reassign reference |
| local final var | Method ke andar constant | ✓ Only final modifier |
✗ static / private / public |
| static final | Class-level constant | ✓ ALL_CAPS naming ✓ Shared across objects |
✗ Reassign anywhere |
Watch out for these in exams!
| Mistake | Wrong ❌ | Sahi ✅ |
|---|---|---|
| Extend final class | class B extends FinalClass |
Possible hi nahi — compile error |
| Override final method | void finalMethod() in child |
Possible hi nahi — compile error |
| Change final variable | final int x=5; x=10; |
Reassign nahi kar sakte |
| Static on local var | static int x = 5; in method |
Remove static from local var |
| final = object immutable | Think final object can't change | Reference fixed, object CAN change! |
| Blank final uninit | final int x; used directly |
Declare + constructor mein set karo |
final keyword likhne padte hain. final class ≠ final variables.final Address a = new Address("Delhi","UP");a.city = "Mumbai"; ← ALLOWED!a = new Address(...); ← ERROR!
final! Local variables pe static, private, public, protected — kuch bhi nahi lag sakta. Sirf final allowed hai.final int x; ← blank final declarationthis.x = 10; ← initialization ✅
equals() override kar sakta tha — bank systems hack ho jaate. java.lang.String, Integer, Math — sab final hain.MAX_SIZE, APP_VERSION, PI, DEBUG_MODE. Yeh ek strong convention hai jo Java community follow karti hai.final Keyword — Complete Revision Guide | All 13 Programs with Explanation