Theory, Memory Model, Access Modifiers, Getters/Setters, Real-World Patterns aur 20+ Practice Programs — sab kuch ek jagah, depth mein.
Complete Theory · OOP Pillar · Why Encapsulate · Real Analogy · Problem Without It
Encapsulation Object-Oriented Programming (OOP) ka ek fundamental pillar hai jisme data (variables/fields) aur us data par kaam karne wale methods ko ek single unit — yani class — ke andar band kiya jaata hai.
Lekin sirf ek unit mein rakhna kaafi nahi. Encapsulation ka dusra aur sabse zaroori part hai — us data ko bahar se directly access hone se rokna (private fields) aur sirf controlled methods (getters/setters) ke through access dena.
Is concept ke 2 parts hain:
private rakho — koi bhi class seedha access na kar sakeData hide karo, controlled access do
Parent se properties lena
Ek naam, alag alag behavior
Implementation chupaana, interface dikhana
Sochte hain koi BankAccount class hai jisme balance field public hai:
account.balance = -99999; — negative balance! No validation possible.balance → accountBalance) to saari jagah change karna padegaclass BankAccount {
// PUBLIC — koi bhi change kar sakta!
public String owner;
public double balance;
public String pin; // 😱 PIN public!
}
// Anywhere in codebase:
BankAccount acc = new BankAccount();
acc.balance = -50000; // No check!
acc.pin = "0000"; // Hack!
System.out.println(acc.pin); // Leak!
class BankAccount {
// PRIVATE — bahar access impossible
private String owner;
private double balance;
private String pin;
public void deposit(double amt) {
if (amt > 0) balance += amt;
}
// PIN never exposed publicly!
}
Sensitive data (PIN, password, SSN) bahar expose nahi hota. Unauthorized access impossible.
Setter mein rules laga sako — negative age, invalid email, overdraft — sab control mein.
Internal implementation change karo bina interface todhe. Users ko pata bhi nahi chalega.
Encapsulated class isolate karke test karna easy hai — mocking aur unit testing simple.
Har class apna kaam kare — SRP (Single Responsibility Principle) naturally follow hoti hai.
Change ek jagah karo, poora codebase safe rahega. Tight coupling avoid hoti hai.
@Getter @Setter se exposeUserBuilder.email().name().build()synchronized setters se thread-safe encapsulated state manage karoprivate · default · protected · public · Scope Rules · Complete Table
Java mein 4 access modifiers hain jo control karte hain ki koi class, method, ya field kahin se accessible hai ya nahi. Ye encapsulation ka technical implementation hain — bina inke encapsulation possible nahi.
Access modifiers sirf class members (fields, methods, constructors) par hi nahi, classes par bhi lagate hain (sirf public ya default — package-private).
Rule of Thumb (Principle of Least Privilege): Hamesha sabse restrictive modifier se shuru karo. private pehli choice, phir zaroorat padne par loosening karo. Kabhi bhi sochke public mat kar do.
| Modifier | Same Class | Same Package | Subclass (diff pkg) | Other Classes | Use For |
|---|---|---|---|---|---|
| private | ✅ Yes | ❌ No | ❌ No | ❌ No | Fields, helper methods |
| default (none) | ✅ Yes | ✅ Yes | ❌ No | ❌ No | Package-internal classes |
| protected | ✅ Yes | ✅ Yes | ✅ Yes | ❌ No | Inheritance, framework base classes |
| public | ✅ Yes | ✅ Yes | ✅ Yes | ✅ Yes | APIs, getters/setters, main method |
// File: AccessDemo.java
class Vehicle {
private String engineSecret = "V8-Turbo"; // sirf Vehicle ke andar
String model = "Sedan"; // default = same package only
protected int year = 2024; // package + subclasses
public String brand = "Toyota"; // everywhere
private void internalDiagnostics() { System.out.println("Internal Check OK"); }
void packageUtil() { System.out.println("Package Util"); }
protected void inheritableMethod() { System.out.println("Inheritable"); }
public void describe() {
// Andar sab accessible hai!
System.out.println("Engine: " + engineSecret); // ✅ private — same class
System.out.println("Model: " + model); // ✅ default — same class
System.out.println("Year: " + year); // ✅ protected — same class
System.out.println("Brand: " + brand); // ✅ public — same class
internalDiagnostics(); // ✅ private — same class
}
}
// Subclass in SAME package
class ElectricCar extends Vehicle {
void showDetails() {
// System.out.println(engineSecret); // ❌ COMPILE ERROR — private
System.out.println("Model: " + model); // ✅ default — same pkg
System.out.println("Year: " + year); // ✅ protected
System.out.println("Brand: " + brand); // ✅ public
inheritableMethod(); // ✅ protected
// internalDiagnostics(); // ❌ COMPILE ERROR — private
}
}
public class AccessDemo {
public static void main(String[] args) {
Vehicle v = new Vehicle();
v.describe(); // ✅ public method call
System.out.println(v.model); // ✅ default — same package
System.out.println(v.year); // ✅ protected — same package
System.out.println(v.brand); // ✅ public
// System.out.println(v.engineSecret); // ❌ private — ERROR!
ElectricCar ec = new ElectricCar();
ec.showDetails();
}
}
JavaBeans Convention · Naming Rules · Read-only · Write-only · Boolean Getter
Getter ek public method hai jo private field ki value return karta hai. Convention: get + FieldName() — jaise getName(), getBalance().
Setter ek public method hai jo private field ko set karta hai — with optional validation. Convention: set + FieldName(value) — jaise setName(String), setAge(int).
Boolean getter special convention: boolean type ke liye get ki jagah is use hota hai — jaise isActive(), isLoggedIn(). Ye JavaBeans specification ka part hai.
Flexibility principle: Ek field ke liye getter de do, setter nahi — read-only field. Ya setter do, getter nahi — write-only (rare, mostly passwords). Ya dono do — read-write. Ya kuch bhi nahi — completely hidden internal state. Ye choice tumhare paas hai!
public class Student {
// ── Private Fields — Direct access IMPOSSIBLE from outside ──
private String name;
private int age;
private double marks;
private boolean isActive;
private String password; // write-only — never returned!
private final String rollNo; // read-only after construction
// ── Constructor ──
public Student(String rollNo, String name, int age) {
this.rollNo = rollNo; // set once, never changeable (final)
this.name = name;
this.age = age;
this.isActive = true;
}
// ── String Getter ──
public String getName() { return name; }
// ── String Setter with Validation ──
public void setName(String name) {
if (name == null || name.trim().isEmpty())
throw new IllegalArgumentException("Name empty nahi ho sakta!");
if (name.length() > 50)
throw new IllegalArgumentException("Name 50 chars se zyada nahi");
this.name = name.trim(); // trim karo whitespace
}
// ── int Getter ──
public int getAge() { return age; }
// ── int Setter with Range Validation ──
public void setAge(int age) {
if (age < 5 || age > 25)
throw new IllegalArgumentException("Age 5-25 ke beech hona chahiye! Got: " + age);
this.age = age;
}
// ── double Getter ──
public double getMarks() { return marks; }
// ── double Setter ──
public void setMarks(double marks) {
if (marks < 0 || marks > 100)
throw new IllegalArgumentException("Marks 0-100 ke beech hone chahiye!");
this.marks = marks;
}
// ── Boolean Getter — NOTE: "is" prefix, not "get" ──
public boolean isActive() { return isActive; }
// ── Boolean Setter ──
public void setActive(boolean active) { this.isActive = active; }
// ── READ-ONLY: rollNo ka getter hai, setter NAHI ──
public String getRollNo() { return rollNo; }
// setRollNo() nahi hai — bahar se change impossible!
// ── WRITE-ONLY: password ka setter hai, getter NAHI ──
public void setPassword(String password) {
if (password.length() < 8)
throw new IllegalArgumentException("Password min 8 chars!");
this.password = password; // store (in real app: hash it!)
}
// getPassword() nahi hai — password kabhi expose nahi hoga!
// ── Computed Getter (no field, derived value) ──
public String getGrade() {
if (marks >= 90) return "A+";
else if (marks >= 80) return "A";
else if (marks >= 70) return "B";
else if (marks >= 60) return "C";
else if (marks >= 45) return "D";
else return "F";
}
@Override
public String toString() {
return String.format("[%s] %s | Age: %d | Marks: %.1f | Grade: %s | Active: %s",
rollNo, name, age, marks, getGrade(), isActive);
}
public static void main(String[] args) {
Student s = new Student("CS001", "Rahul Sharma", 20);
s.setMarks(87.5);
s.setPassword("mypass123");
System.out.println(s);
// Read-only test
System.out.println("Roll No: " + s.getRollNo());
// s.setRollNo("XX999"); // ❌ COMPILE ERROR — method doesn't exist!
// Boolean getter
System.out.println("Is Active: " + s.isActive());
s.setActive(false);
System.out.println("After deactivate: " + s.isActive());
// Validation test
try {
s.setAge(150); // invalid!
} catch (IllegalArgumentException e) {
System.out.println("Caught: " + e.getMessage());
}
// Computed getter
System.out.println("Computed Grade: " + s.getGrade());
}
}
Business Rules · Exception Handling · Custom Validators · Defensive Programming
Setter sirf assignment ke liye nahi hai — ye data integrity ki guarantee hai. Jab bhi koi field set ho, business rules satisfy hone chahiye. Ye ek single validated entry point hai.
Good setter mein hona chahiye:
if (value == null) throw...public class BankAccount {
private String accountNumber;
private String owner;
private double balance;
private String pin;
private boolean isLocked;
private int failedAttempts;
private static final double MIN_BALANCE = 500.0;
private static final double MAX_DEPOSIT = 100000.0;
private static final int MAX_FAILED_ATTEMPTS = 3;
public BankAccount(String accNum, String owner, double initialBalance, String pin) {
if (initialBalance < MIN_BALANCE)
throw new IllegalArgumentException("Initial balance minimum Rs " + MIN_BALANCE + " hona chahiye!");
this.accountNumber = accNum;
this.owner = owner;
this.balance = initialBalance;
setPin(pin); // validation ke saath!
}
// ── PIN Setter — strength validation ──
public void setPin(String pin) {
if (pin == null) throw new IllegalArgumentException("PIN null nahi ho sakta");
if (!pin.matches("\\d{4,6}"))
throw new IllegalArgumentException("PIN sirf 4-6 digits ka hona chahiye!");
if (pin.equals("0000") || pin.equals("1234") || pin.equals("1111"))
throw new IllegalArgumentException("PIN too simple! Use a strong PIN.");
this.pin = pin; // In real app: hash this!
}
// ── Deposit — amount validation ──
public void deposit(double amount) {
if (isLocked) throw new IllegalStateException("Account locked! Unlock karo pehle.");
if (amount <= 0) throw new IllegalArgumentException("Deposit amount positive hona chahiye!");
if (amount > MAX_DEPOSIT) throw new IllegalArgumentException("Single deposit max Rs " + MAX_DEPOSIT);
this.balance += amount;
System.out.println("✅ Deposited Rs " + amount + ". New balance: " + balance);
}
// ── Withdraw — multiple validations ──
public void withdraw(double amount, String enteredPin) {
if (isLocked) throw new IllegalStateException("Account locked!");
if (!verifyPin(enteredPin)) return; // pin verify internally
if (amount <= 0) throw new IllegalArgumentException("Withdrawal amount positive hona chahiye!");
if (amount > balance) throw new IllegalStateException("Insufficient balance!");
if ((balance - amount) < MIN_BALANCE)
throw new IllegalStateException("Minimum balance Rs " + MIN_BALANCE + " maintain karna zaroori hai!");
this.balance -= amount;
System.out.println("✅ Withdrawn Rs " + amount + ". New balance: " + balance);
}
// ── Private PIN verifier — internal logic hidden! ──
private boolean verifyPin(String entered) {
if (!pin.equals(entered)) {
failedAttempts++;
System.out.println("❌ Wrong PIN! Attempts left: " + (MAX_FAILED_ATTEMPTS - failedAttempts));
if (failedAttempts >= MAX_FAILED_ATTEMPTS) {
isLocked = true;
System.out.println("🔒 Account LOCKED after " + MAX_FAILED_ATTEMPTS + " failed attempts!");
}
return false;
}
failedAttempts = 0; // reset on success
return true;
}
public double getBalance() { return balance; }
public String getOwner() { return owner; }
public String getAccountNumber() { return accountNumber; }
public boolean isLocked() { return isLocked; }
// getPin() — NEVER! Password/PIN ke liye getter mat banao
public static void main(String[] args) {
BankAccount acc = new BankAccount("ACC123", "Rahul", 5000.0, "9876");
System.out.println("Owner: " + acc.getOwner() + ", Balance: " + acc.getBalance());
acc.deposit(2000);
acc.withdraw(500, "9876");
// Wrong PIN attempts
acc.withdraw(100, "0000");
acc.withdraw(100, "1111");
acc.withdraw(100, "2222"); // 3rd wrong → lock!
try {
acc.deposit(100); // locked!
} catch (IllegalStateException e) {
System.out.println("Error: " + e.getMessage());
}
try {
BankAccount weak = new BankAccount("ACC456", "Test", 1000, "1234");
} catch (IllegalArgumentException e) {
System.out.println("PIN Error: " + e.getMessage());
}
}
}
Parameterized Constructor · Constructor Overloading · this() Chaining · Mandatory Fields
Constructor encapsulation ka extension hai — ye ensure karta hai ki object birth se hi valid state mein ho. Agar fields mandatory hain, constructor mein force karo — default constructor mat dena.
Private Constructor: Singleton pattern mein use hota hai — bahar se new impossible! Factory method se instance milta hai.
Constructor Chaining (this()): Ek constructor dusre ko call kare — code duplication avoid hoti hai. this() hamesha pehli line honi chahiye.
public class Employee {
private final String empId; // mandatory — no setter
private String name;
private String department;
private double salary;
private int experienceYears;
// ── Constructor 1: Most detailed (base constructor) ──
public Employee(String empId, String name, String dept, double salary, int exp) {
if (empId == null || empId.trim().isEmpty())
throw new IllegalArgumentException("Employee ID mandatory hai!");
if (name == null || name.trim().isEmpty())
throw new IllegalArgumentException("Name mandatory hai!");
if (salary < 0)
throw new IllegalArgumentException("Salary negative nahi ho sakti!");
this.empId = empId.toUpperCase();
this.name = name.trim();
this.department = dept != null ? dept : "General";
this.salary = salary;
this.experienceYears = exp;
}
// ── Constructor 2: Without experience (chains to Constructor 1) ──
public Employee(String empId, String name, String dept, double salary) {
this(empId, name, dept, salary, 0); // this() — pehli line MUST
}
// ── Constructor 3: Minimum — id + name only ──
public Employee(String empId, String name) {
this(empId, name, "General", 30000.0, 0); // defaults for rest
}
// ── Getters ──
public String getEmpId() { return empId; }
public String getName() { return name; }
public String getDepartment() { return department; }
public double getSalary() { return salary; }
public int getExperienceYears() { return experienceYears; }
// ── Setters with validation ──
public void setName(String name) {
if (name == null || name.trim().isEmpty()) throw new IllegalArgumentException("Name blank nahi ho sakta");
this.name = name.trim();
}
public void setDepartment(String dept) { this.department = dept; }
public void setSalary(double salary) {
if (salary < 0) throw new IllegalArgumentException("Salary negative nahi ho sakti!");
if (salary < this.salary * 0.5) throw new IllegalArgumentException("Salary 50% se zyada reduce nahi ho sakti!");
this.salary = salary;
}
// ── Business Method ──
public void promote(double percentageHike) {
if (percentageHike <= 0 || percentageHike > 100)
throw new IllegalArgumentException("Hike 0-100% ke beech hona chahiye!");
double newSalary = salary * (1 + percentageHike / 100);
System.out.printf("🎉 %s promoted! Salary: %.0f → %.0f (%.0f%% hike)%n",
name, salary, newSalary, percentageHike);
this.salary = newSalary;
this.experienceYears++;
}
@Override
public String toString() {
return String.format("Employee{id='%s', name='%s', dept='%s', salary=%.0f, exp=%d yrs}",
empId, name, department, salary, experienceYears);
}
public static void main(String[] args) {
// Different constructors
Employee e1 = new Employee("EMP001", "Rahul", "Engineering", 75000, 3);
Employee e2 = new Employee("EMP002", "Priya", "Marketing", 60000);
Employee e3 = new Employee("EMP003", "Amit"); // minimum
System.out.println(e1);
System.out.println(e2);
System.out.println(e3);
e1.promote(15);
System.out.println(e1);
// Salary reduction >50% reject
try {
e2.setSalary(10000); // 60000 → 10000 = too much drop
} catch (IllegalArgumentException ex) {
System.out.println("Salary Error: " + ex.getMessage());
}
}
}
Disambiguation · Method Chaining · this() Constructor Call · Pass Current Object
this keyword current class ke instance ka reference hai. Encapsulation ke context mein ye mostly getter/setter mein use hota hai jab local variable (parameter) aur instance variable ka naam same ho.
this.name = name — left side instance variable, right side parameterthis(args) — ek constructor se dusra call karoreturn this — method khud return kare for chainingsomeMethod(this) — apne aap ko argument ke roop mein denapublic class UserProfile {
private String username;
private String email;
private int age;
private String city;
private boolean newsletter;
// ── USE 1: Ambiguity resolve — parameter naam same hai field se ──
public void setUsername(String username) { // param: username
this.username = username; // this.username = instance field
// Bina this: "username = username" kuch nahi karega (local = local)
}
public void setEmail(String email) {
if (!email.contains("@")) throw new IllegalArgumentException("Invalid email!");
this.email = email.toLowerCase();
}
// ── USE 3: Method Chaining — return this! ──
// Har setter this return karta hai → ek ke baad ek call kar sako
public UserProfile withAge(int age) {
if (age < 13 || age > 120) throw new IllegalArgumentException("Invalid age!");
this.age = age;
return this; // ← KEY — current object return karo
}
public UserProfile inCity(String city) {
this.city = city;
return this;
}
public UserProfile subscribeNewsletter(boolean subscribe) {
this.newsletter = subscribe;
return this;
}
public UserProfile withEmail(String email) {
setEmail(email); // reuse existing setter with validation
return this;
}
// ── USE 4: Pass current object to another method ──
public void registerWith(UserRegistry registry) {
registry.register(this); // apne aap ko registry ko dedo
}
public String getUsername() { return username; }
public String getEmail() { return email; }
public int getAge() { return age; }
public String getCity() { return city; }
public boolean isNewsletter(){ return newsletter; }
@Override
public String toString() {
return String.format(
"UserProfile{user='%s', email='%s', age=%d, city='%s', newsletter=%s}",
username, email, age, city, newsletter);
}
public static void main(String[] args) {
// Method chaining — ek line mein sab set karo!
UserProfile user = new UserProfile();
user.setUsername("rahul_dev");
// Chained calls — clean, readable!
user.withEmail("rahul@example.com")
.withAge(25)
.inCity("Indore")
.subscribeNewsletter(true);
System.out.println(user);
// Another user — one-liner!
UserProfile admin = new UserProfile();
admin.setUsername("admin");
admin.withEmail("admin@company.com").withAge(30).inCity("Mumbai").subscribeNewsletter(false);
System.out.println(admin);
}
}
// Helper class for USE 4 demo
class UserRegistry {
public void register(UserProfile user) {
System.out.println("Registered: " + user.getUsername() + " from " + user.getCity());
}
}
final Fields · No Setters · Deep Immutability · Thread Safety · Value Objects
Ek immutable class ka object create hone ke baad uski state kabhi bhi change nahi hoti. Java ka String, Integer, LocalDate — sab immutable hain.
Immutable class banane ke 5 rules:
final banao — subclassing prevent hoti haiprivate final karoBenefits: Thread-safe by default (no synchronization needed!), safe for caching, HashMap keys ke liye perfect, reasoning easy hai.
public final class Money { // final — subclassing prevent
private final double amount; // final — ek baar set, never change
private final String currency;
public Money(double amount, String currency) {
if (amount < 0) throw new IllegalArgumentException("Amount negative nahi ho sakta!");
if (currency == null || currency.trim().isEmpty())
throw new IllegalArgumentException("Currency code required!");
this.amount = amount;
this.currency = currency.toUpperCase();
}
// ── Getters only — NO setters! ──
public double getAmount() { return amount; }
public String getCurrency() { return currency; }
// ── Operations return NEW Money object — original unchanged! ──
public Money add(Money other) {
if (!currency.equals(other.currency))
throw new IllegalArgumentException("Alag currencies add nahi kar sakte!");
return new Money(amount + other.amount, currency); // NEW object!
}
public Money subtract(Money other) {
if (!currency.equals(other.currency)) throw new IllegalArgumentException("Currency mismatch!");
if (amount < other.amount) throw new IllegalArgumentException("Insufficient!");
return new Money(amount - other.amount, currency);
}
public Money multiply(double factor) {
if (factor < 0) throw new IllegalArgumentException("Factor negative nahi ho sakta!");
return new Money(amount * factor, currency);
}
public boolean isGreaterThan(Money other) { return this.amount > other.amount; }
public boolean isZero() { return amount == 0; }
@Override
public String toString() {
return String.format("%s %.2f", currency, amount);
}
public static void main(String[] args) {
Money price = new Money(1000.0, "INR");
Money tax = new Money(180.0, "INR");
Money discount= new Money(50.0, "INR");
System.out.println("Price: " + price);
System.out.println("Tax (18%): " + tax);
System.out.println("Discount: " + discount);
Money total = price.add(tax).subtract(discount); // chaining!
System.out.println("Total: " + total);
System.out.println("Price unchanged: " + price); // original safe!
Money doubled = price.multiply(2);
System.out.println("Doubled price: " + doubled);
// Currency mismatch test
try {
Money usd = new Money(10, "USD");
price.add(usd); // different currencies!
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
Library System · E-Commerce Product · Hospital Patient · Builder Pattern
import java.time.LocalDate;
import java.time.temporal.ChronoUnit;
public class LibraryBook {
private final String isbn;
private final String title;
private final String author;
private boolean isAvailable;
private String borrowedBy;
private LocalDate issueDate;
private int totalIssues;
private static final int MAX_DAYS = 14; // 2 weeks
private static final double FINE_PER_DAY = 5.0;
public LibraryBook(String isbn, String title, String author) {
if (isbn == null || title == null || author == null)
throw new IllegalArgumentException("ISBN, title, author all mandatory!");
this.isbn = isbn;
this.title = title;
this.author = author;
this.isAvailable = true;
}
public void issueBook(String memberName) {
if (!isAvailable)
throw new IllegalStateException("Book already issued to: " + borrowedBy);
if (memberName == null || memberName.trim().isEmpty())
throw new IllegalArgumentException("Member name required!");
this.borrowedBy = memberName;
this.issueDate = LocalDate.now();
this.isAvailable = false;
this.totalIssues++;
System.out.printf("📖 '%s' issued to %s on %s. Due: %s%n",
title, memberName, issueDate, issueDate.plusDays(MAX_DAYS));
}
public void returnBook() {
if (isAvailable) throw new IllegalStateException("Book pehle se available hai!");
long daysHeld = ChronoUnit.DAYS.between(issueDate, LocalDate.now());
long overdue = Math.max(0, daysHeld - MAX_DAYS);
double fine = overdue * FINE_PER_DAY;
System.out.printf("✅ '%s' returned by %s. Days held: %d", title, borrowedBy, daysHeld);
if (fine > 0) System.out.printf(", Overdue: %d days, Fine: Rs %.0f", overdue, fine);
System.out.println();
this.isAvailable = true;
this.borrowedBy = null;
this.issueDate = null;
}
public String getIsbn() { return isbn; }
public String getTitle() { return title; }
public String getAuthor() { return author; }
public boolean isAvailable() { return isAvailable; }
public int getTotalIssues() { return totalIssues; }
public String getBorrowedBy() { return isAvailable ? "Available" : borrowedBy; }
public static void main(String[] args) {
LibraryBook book = new LibraryBook("978-0134685991", "Effective Java", "Joshua Bloch");
System.out.println("Available: " + book.isAvailable());
book.issueBook("Rahul Sharma");
System.out.println("Borrowed By: " + book.getBorrowedBy());
try {
book.issueBook("Priya"); // already issued!
} catch (IllegalStateException e) {
System.out.println("Issue Error: " + e.getMessage());
}
book.returnBook();
System.out.println("Total issues: " + book.getTotalIssues());
book.issueBook("Priya Patel"); // now possible
}
}
DOs and DON'Ts · SOLID · Common Mistakes · Interview Tips
private rakho — default ruletoString() override karo debugging ke liyeis prefix convention follow karoprivate static final karopublic static mutable fields — worst practicepublic int[] getScores() { return scores; } — caller array modify kar sakta hai directly! Fix: return Arrays.copyOf(scores, scores.length); — defensive copy return karo.@Getter @Setter @NoArgsConstructor @AllArgsConstructor annotations se automatically getters/setters generate hote hain. Ye Lombok library hai. Lekin validation ke liye phir bhi custom setter likhna padta hai.Topic-wise 4-5 Problems · Click to See Solution · Beginner to Advanced
Private fields, getters, setters, toString — fundamentals solid karo
public class Rectangle {
private double length;
private double width;
public Rectangle(double length, double width) {
setLength(length);
setWidth(width);
}
public double getLength() { return length; }
public double getWidth() { return width; }
public void setLength(double length) {
if (length <= 0) throw new IllegalArgumentException("Length positive hona chahiye! Got: " + length);
this.length = length;
}
public void setWidth(double width) {
if (width <= 0) throw new IllegalArgumentException("Width positive hona chahiye! Got: " + width);
this.width = width;
}
// Computed — no separate fields needed
public double getArea() { return length * width; }
public double getPerimeter() { return 2 * (length + width); }
public boolean isSquare() { return length == width; }
@Override
public String toString() {
return String.format(
"Rectangle[%.1f × %.1f] | Area=%.2f | Perimeter=%.2f | Square=%s",
length, width, getArea(), getPerimeter(), isSquare());
}
public static void main(String[] args) {
Rectangle r1 = new Rectangle(5, 3);
Rectangle r2 = new Rectangle(4, 4);
System.out.println(r1);
System.out.println(r2);
r1.setLength(10);
System.out.println("After resize: " + r1);
try {
new Rectangle(-2, 5);
} catch (IllegalArgumentException e) {
System.out.println("Error: " + e.getMessage());
}
}
}
public class Person {
private String name;
private int age;
private String email;
public Person(String name, int age, String email) {
setName(name); setAge(age); setEmail(email);
}
public String getName() { return name; }
public int getAge() { return age; }
public String getEmail() { return email; }
public void setName(String name) {
if (name == null || name.trim().isEmpty())
throw new IllegalArgumentException("Name required!");
// Auto title-case: "rahul sharma" → "Rahul Sharma"
String[] parts = name.trim().split("\\s+");
StringBuilder sb = new StringBuilder();
for (String p : parts) {
if (!p.isEmpty()) sb.append(Character.toUpperCase(p.charAt(0)))
.append(p.substring(1).toLowerCase()).append(" ");
}
this.name = sb.toString().trim();
}
public void setAge(int age) {
if (age < 1 || age > 120)
throw new IllegalArgumentException("Age 1-120 ke beech hona chahiye!");
this.age = age;
}
public void setEmail(String email) {
if (email == null || !email.contains("@") || !email.contains("."))
throw new IllegalArgumentException("Valid email required (must have @ and .)");
this.email = email.toLowerCase().trim();
}
public String getCategory() {
if (age < 13) return "Child";
else if (age < 18) return "Teenager";
else if (age < 60) return "Adult";
else return "Senior";
}
@Override
public String toString() {
return String.format("Person{name='%s', age=%d (%s), email='%s'}",
name, age, getCategory(), email);
}
public static void main(String[] args) {
Person p = new Person("rahul SHARMA", 25, "RAHUL@Gmail.Com");
System.out.println(p); // name auto-formatted, email lowercase
try { new Person("Test", 200, "test@a.com"); }
catch (IllegalArgumentException e) { System.out.println("Age Error: "+e.getMessage()); }
try { new Person("Test", 20, "invalidemail"); }
catch (IllegalArgumentException e) { System.out.println("Email Error: "+e.getMessage()); }
}
}
public class Counter {
private int count;
private final int minValue;
private final int maxValue;
private int totalIncrements;
private int totalDecrements;
public Counter(int initial, int min, int max) {
if (min >= max) throw new IllegalArgumentException("min must be < max!");
if (initial < min || initial > max)
throw new IllegalArgumentException("Initial must be in [min, max]");
this.count = initial; this.minValue = min; this.maxValue = max;
}
public Counter() { this(0, 0, Integer.MAX_VALUE); } // default
public boolean increment() {
if (count >= maxValue) { System.out.println("Max ("+maxValue+") reached!"); return false; }
count++; totalIncrements++; return true;
}
public boolean decrement() {
if (count <= minValue) { System.out.println("Min ("+minValue+") reached!"); return false; }
count--; totalDecrements++; return true;
}
public void incrementBy(int n) { for (int i=0; iif(!increment()) break; }
public void reset() { count = minValue; }
public int getCount() { return count; }
public int getTotalIncrements() { return totalIncrements; }
public int getTotalDecrements() { return totalDecrements; }
public boolean isAtMax() { return count == maxValue; }
public boolean isAtMin() { return count == minValue; }
@Override
public String toString() {
return String.format("Counter{count=%d, range=[%d,%d], +%d, -%d}",
count, minValue, maxValue, totalIncrements, totalDecrements);
}
public static void main(String[] args) {
Counter c = new Counter(0, 0, 5);
c.incrementBy(7); // only goes to 5
System.out.println(c);
c.decrement(); c.decrement();
System.out.println(c);
c.reset();
System.out.println("After reset: " + c.getCount());
for (int i=0; i<3; i++) c.decrement(); // only 1 works
}
}
public class Circle {
private double radius;
private static final double PI = Math.PI;
public Circle(double radius) { setRadius(radius); }
public double getRadius() { return radius; }
public void setRadius(double radius) {
if (radius <= 0) throw new IllegalArgumentException("Radius must be positive!");
this.radius = radius;
}
public double getArea() { return PI * radius * radius; }
public double getCircumference() { return 2 * PI * radius; }
public double getDiameter() { return 2 * radius; }
public boolean isLargerThan(Circle other) { return this.getArea() > other.getArea(); }
public boolean canFitInside(Circle other) { return this.radius < other.radius; }
public boolean intersectsWith(Circle other, double distBetweenCenters) {
return distBetweenCenters < (this.radius + other.radius);
}
@Override
public String toString() {
return String.format("Circle[r=%.1f | area=%.2f | circumf=%.2f]",
radius, getArea(), getCircumference());
}
public static void main(String[] args) {
Circle c1 = new Circle(5.0);
Circle c2 = new Circle(3.0);
System.out.println(c1);
System.out.println(c2);
System.out.println("c1 larger than c2: " + c1.isLargerThan(c2));
System.out.println("c2 fits in c1: " + c2.canFitInside(c1));
System.out.println("Intersect (d=6): " + c1.intersectsWith(c2, 6));
}
}
Domain-driven classes with complete business logic
public class Product {
private final String productId;
private String name;
private double price;
private int stock;
private double discountPercent;
private int totalSold;
public Product(String id, String name, double price, int stock) {
this.productId = id;
setName(name); setPrice(price); restock(stock);
}
public void setName(String name) {
if (name == null || name.trim().isEmpty()) throw new IllegalArgumentException("Name required!");
this.name = name.trim();
}
public void setPrice(double price) {
if (price < 0) throw new IllegalArgumentException("Price negative nahi ho sakti!");
this.price = price;
}
public void applyDiscount(double percent) {
if (percent < 0 || percent > 90) throw new IllegalArgumentException("Discount 0-90% ke beech!");
this.discountPercent = percent;
System.out.printf("💰 %s pe %.0f%% discount applied! Effective price: Rs %.2f%n",
name, percent, getEffectivePrice());
}
public double getEffectivePrice() { return price * (1 - discountPercent / 100); }
public void restock(int qty) {
if (qty <= 0) throw new IllegalArgumentException("Restock qty positive hona chahiye!");
stock += qty;
System.out.println("📦 " + name + ": Restocked " + qty + ". Total stock: " + stock);
}
public boolean buy(int qty) {
if (qty <= 0) { System.out.println("Invalid qty!"); return false; }
if (stock < qty) { System.out.println("❌ Insufficient stock! Available: "+stock); return false; }
stock -= qty;
totalSold += qty;
System.out.printf("🛒 Bought %d x %s @ Rs %.2f each. Total: Rs %.2f%n",
qty, name, getEffectivePrice(), qty * getEffectivePrice());
if (stock < 5) System.out.println("⚠️ Low stock alert! Only " + stock + " left.");
return true;
}
public String getProductId() { return productId; }
public String getName() { return name; }
public double getPrice() { return price; }
public int getStock() { return stock; }
public int getTotalSold() { return totalSold; }
public boolean isOutOfStock() { return stock == 0; }
@Override
public String toString() {
return String.format("[%s] %s | MRP:Rs%.0f | Eff:Rs%.2f | Stock:%d | Sold:%d",
productId, name, price, getEffectivePrice(), stock, totalSold);
}
public static void main(String[] args) {
Product p = new Product("PROD001", "Laptop", 55000, 10);
System.out.println(p);
p.applyDiscount(15);
p.buy(3);
p.buy(5);
p.buy(4); // insufficient
System.out.println(p);
}
}
public class Car {
private final String brand;
private final String model;
private double fuelLevel; // liters
private int speed; // km/h
private int gear; // 1-6
private boolean engineOn;
private static final double MAX_FUEL = 50.0;
private static final int MAX_SPEED = 200;
private static final double FUEL_PER_KM = 0.08;
public Car(String brand, String model) {
this.brand = brand; this.model = model;
this.fuelLevel = MAX_FUEL; this.gear = 1;
}
public void startEngine() {
if (fuelLevel <= 0) { System.out.println("⛽ No fuel! Cannot start."); return; }
engineOn = true; System.out.println("🔑 Engine started! Vroom...");
}
public void accelerate(int amount) {
if (!engineOn) { System.out.println("Start engine first!"); return; }
if (fuelLevel <= 1.0) { System.out.println("⚠️ Low fuel! Speed maintained."); return; }
if (amount <= 0) throw new IllegalArgumentException("Acceleration positive hona chahiye!");
speed = Math.min(speed + amount, MAX_SPEED);
fuelLevel -= amount * FUEL_PER_KM * 0.5;
fuelLevel = Math.max(0, fuelLevel);
System.out.printf("🚗 Speed: %d km/h | Fuel: %.1f L | Gear: %d%n", speed, fuelLevel, gear);
}
public void brake(int amount) {
speed = Math.max(0, speed - amount);
if (speed == 0) { engineOn = false; System.out.println("🛑 Stopped."); }
else System.out.println("Speed reduced to: " + speed + " km/h");
}
public void shiftGear(int newGear) {
if (newGear < 1 || newGear > 6) throw new IllegalArgumentException("Gear 1-6 ke beech!");
if (Math.abs(newGear - gear) > 1) { System.out.println("⚠️ Skip gear not recommended!"); }
gear = newGear; System.out.println("Gear shifted to: " + gear);
}
public void refuel(double liters) {
if (liters <= 0) throw new IllegalArgumentException("Refuel amount positive hona chahiye!");
fuelLevel = Math.min(fuelLevel + liters, MAX_FUEL);
System.out.printf("⛽ Refueled. Fuel: %.1f/%.1f L%n", fuelLevel, MAX_FUEL);
}
public String getBrand() { return brand; }
public String getModel() { return model; }
public int getSpeed() { return speed; }
public double getFuelLevel() { return fuelLevel; }
public int getGear() { return gear; }
public boolean isEngineOn() { return engineOn; }
public static void main(String[] args) {
Car car = new Car("Maruti", "Swift");
car.startEngine();
car.accelerate(40);
car.shiftGear(2);
car.accelerate(60);
car.shiftGear(3);
car.accelerate(80);
car.brake(50);
car.brake(130);
}
}
public class Temperature {
private double celsius; // internal storage always Celsius
private static final double ABSOLUTE_ZERO_C = -273.15;
private Temperature(double celsius) { setCelsius(celsius); }
// Factory Methods — create from any unit
public static Temperature fromCelsius(double c) { return new Temperature(c); }
public static Temperature fromFahrenheit(double f) { return new Temperature((f - 32) * 5 / 9); }
public static Temperature fromKelvin(double k) { return new Temperature(k + ABSOLUTE_ZERO_C); }
public void setCelsius(double celsius) {
if (celsius < ABSOLUTE_ZERO_C)
throw new IllegalArgumentException("Absolute zero ("+ABSOLUTE_ZERO_C+"°C) se neeche nahi ja sakte!");
this.celsius = celsius;
}
// Getters in all 3 formats
public double getCelsius() { return celsius; }
public double getFahrenheit() { return celsius * 9 / 5 + 32; }
public double getKelvin() { return celsius - ABSOLUTE_ZERO_C; }
public String getState() {
if (celsius <= 0) return "Ice ❄️";
else if (celsius < 100) return "Liquid 💧";
else return "Steam 💨";
}
@Override
public String toString() {
return String.format("%.2f°C = %.2f°F = %.2fK [%s]",
celsius, getFahrenheit(), getKelvin(), getState());
}
public static void main(String[] args) {
System.out.println(Temperature.fromCelsius(100));
System.out.println(Temperature.fromCelsius(0));
System.out.println(Temperature.fromFahrenheit(98.6)); // body temp
System.out.println(Temperature.fromKelvin(0)); // absolute zero
try {
Temperature.fromCelsius(-300); // below absolute zero!
} catch (IllegalArgumentException e) { System.out.println("Error: " + e.getMessage()); }
}
}
Immutability, Builder, Singleton — interview-level problems
import java.util.HashMap;
import java.util.Map;
public class AppConfig {
// Single instance — private static
private static AppConfig instance;
// Private fields
private final Map<String, String> configs;
private String environment;
private boolean debugMode;
// PRIVATE constructor — new AppConfig() bahar se IMPOSSIBLE!
private AppConfig() {
configs = new HashMap<>();
environment = "development";
debugMode = false;
loadDefaults();
System.out.println("⚙️ AppConfig initialized (only once!)");
}
private void loadDefaults() {
configs.put("db.host", "localhost");
configs.put("db.port", "5432");
configs.put("app.version", "1.0.0");
configs.put("max.threads", "10");
}
// Public access point — ONLY WAY to get instance
public static synchronized AppConfig getInstance() {
if (instance == null) {
instance = new AppConfig(); // lazy init — sirf pehli baar
}
return instance;
}
public String get(String key) { return configs.getOrDefault(key, "NOT_FOUND"); }
public void set(String key, String value) { configs.put(key, value); }
public int getInt(String key) { return Integer.parseInt(get(key)); }
public String getEnvironment() { return environment; }
public void setEnvironment(String env) {
if (!env.matches("development|staging|production"))
throw new IllegalArgumentException("Valid env: development, staging, production");
this.environment = env;
}
public boolean isDebugMode() { return debugMode; }
public void setDebugMode(boolean debug) { this.debugMode = debug; }
public static void main(String[] args) {
// getInstance() hi ek way hai
AppConfig config1 = AppConfig.getInstance();
AppConfig config2 = AppConfig.getInstance();
System.out.println("Same instance? " + (config1 == config2)); // true!
config1.set("db.host", "prod-server.db.com");
config1.setEnvironment("production");
config1.setDebugMode(false);
// config2 pe access karo — same data!
System.out.println("DB Host: " + config2.get("db.host"));
System.out.println("Env: " + config2.getEnvironment());
System.out.println("Threads: " + config2.getInt("max.threads"));
try {
config1.setEnvironment("invalid"); // invalid env
} catch (IllegalArgumentException e) {
System.out.println("Env Error: " + e.getMessage());
}
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Pizza {
// Immutable fields — set once via Builder
private final String size;
private final String crust;
private final String sauce;
private final List<String> toppings;
private final boolean extraCheese;
private final double price;
// PRIVATE constructor — sirf Builder se banana possible!
private Pizza(Builder b) {
this.size = b.size;
this.crust = b.crust;
this.sauce = b.sauce;
this.toppings = Collections.unmodifiableList(new ArrayList<>(b.toppings));
this.extraCheese = b.extraCheese;
this.price = b.calculatePrice();
}
// ── Getters only — fully immutable ──
public String getSize() { return size; }
public String getCrust() { return crust; }
public String getSauce() { return sauce; }
public List<String> getToppings() { return toppings; }
public boolean isExtraCheese() { return extraCheese; }
public double getPrice() { return price; }
@Override
public String toString() {
return String.format(
"🍕 %s Pizza | Crust: %s | Sauce: %s | Toppings: %s | ExtraCheese: %s | Price: Rs %.0f",
size, crust, sauce, toppings, extraCheese, price);
}
// ── STATIC INNER BUILDER CLASS ──
public static class Builder {
// Required
private final String size;
// Optional with defaults
private String crust = "Thin";
private String sauce = "Tomato";
private List<String> toppings = new ArrayList<>();
private boolean extraCheese = false;
public Builder(String size) {
if (!size.matches("Small|Medium|Large"))
throw new IllegalArgumentException("Size: Small, Medium, Large only!");
this.size = size;
}
public Builder crust(String crust) { this.crust = crust; return this; }
public Builder sauce(String sauce) { this.sauce = sauce; return this; }
public Builder addTopping(String t) {
if (toppings.size() >= 5) throw new IllegalStateException("Max 5 toppings!");
toppings.add(t); return this;
}
public Builder extraCheese() { this.extraCheese = true; return this; }
double calculatePrice() {
double base = size.equals("Small") ? 199 : size.equals("Medium") ? 299 : 399;
return base + toppings.size() * 30 + (extraCheese ? 50 : 0);
}
public Pizza build() { return new Pizza(this); }
}
public static void main(String[] args) {
// Builder pattern — readable, step by step
Pizza p1 = new Pizza.Builder("Large")
.crust("Thick")
.sauce("BBQ")
.addTopping("Mushrooms")
.addTopping("Peppers")
.addTopping("Onions")
.extraCheese()
.build();
System.out.println(p1);
Pizza p2 = new Pizza.Builder("Small")
.addTopping("Paneer")
.build(); // defaults for rest
System.out.println(p2);
}
}
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class Patient {
private final String patientId;
private final String name;
private final int age;
private final String bloodGroup;
private double weight;
private double height;
private final List<String> prescriptions = new ArrayList<>();
private final List<String> allergies = new ArrayList<>();
private boolean criticalStatus;
private static final String[] VALID_BLOOD_GROUPS =
{"A+","A-","B+","B-","AB+","AB-","O+","O-"};
public Patient(String id, String name, int age, String bloodGroup, double wt, double ht) {
if (age < 0 || age > 150) throw new IllegalArgumentException("Invalid age!");
if (!isValidBloodGroup(bloodGroup)) throw new IllegalArgumentException("Invalid blood group!");
if (wt <= 0 || ht <= 0) throw new IllegalArgumentException("Weight/Height positive hona chahiye!");
this.patientId = id; this.name = name; this.age = age;
this.bloodGroup = bloodGroup; this.weight = wt; this.height = ht;
}
private boolean isValidBloodGroup(String bg) {
for (String valid : VALID_BLOOD_GROUPS) if (valid.equals(bg)) return true;
return false;
}
// Doctor privilege method — structured prescription
public void addPrescription(String medicine, String dosage, String doctorId) {
if (medicine == null || medicine.trim().isEmpty())
throw new IllegalArgumentException("Medicine name required!");
prescriptions.add(String.format("%s | %s | Dr.%s", medicine.trim(), dosage, doctorId));
System.out.println("💊 Prescription added: " + medicine);
}
public void addAllergy(String allergen) {
if (allergen == null || allergen.trim().isEmpty())
throw new IllegalArgumentException("Allergen name required!");
allergies.add(allergen.trim());
System.out.println("⚠️ Allergy recorded: " + allergen);
}
public double getBMI() { return weight / (height * height); }
public String getBMICategory() {
double bmi = getBMI();
if (bmi < 18.5) return "Underweight";
else if (bmi < 25.0) return "Normal";
else if (bmi < 30.0) return "Overweight";
else return "Obese";
}
// Getters
public String getPatientId() { return patientId; }
public String getName() { return name; }
public int getAge() { return age; }
public String getBloodGroup() { return bloodGroup; }
public double getWeight() { return weight; }
public boolean isCritical() { return criticalStatus; }
public void setCritical(boolean c) { this.criticalStatus = c; }
// Defensive copy — caller cannot modify internal list
public List<String> getPrescriptions() { return Collections.unmodifiableList(prescriptions); }
public List<String> getAllergies() { return Collections.unmodifiableList(allergies); }
public void printSummary() {
System.out.println("\n═══════════ PATIENT SUMMARY ═══════════");
System.out.printf("ID: %s | Name: %s | Age: %d%n", patientId, name, age);
System.out.printf("Blood: %s | Weight: %.1fkg | BMI: %.1f (%s)%n",
bloodGroup, weight, getBMI(), getBMICategory());
System.out.println("Status: " + (criticalStatus ? "🔴 CRITICAL" : "🟢 Stable"));
System.out.println("Allergies: " + (allergies.isEmpty() ? "None" : allergies));
System.out.println("Prescriptions:");
for (String rx : prescriptions) System.out.println(" • " + rx);
System.out.println("════════════════════════════════════════");
}
public static void main(String[] args) {
Patient p = new Patient("PAT001", "Rahul Gupta", 35, "A+", 75.5, 1.75);
p.addAllergy("Penicillin");
p.addAllergy("Dust");
p.addPrescription("Paracetamol", "500mg x 3/day", "DR123");
p.addPrescription("Vitamin D", "1000IU x 1/day", "DR123");
p.printSummary();
try {
p.getPrescriptions().add("Hacked!"); // unmodifiable!
} catch (UnsupportedOperationException e) {
System.out.println("Cannot modify prescriptions directly! " + e.getClass().getSimpleName());
}
}
}
public List<String> getItems() { return items; } — caller list modify kar sakta hai! Fix: return Collections.unmodifiableList(items); ya return new ArrayList<>(items);getPassword() ya getPin() mat banao. Password/PIN sirf setter se set ho, verify ke liye private helper method use karo jo sirf boolean return kare.this.x = x karta hai bina validation ke, aur field directly accessible hoga to encapsulation ka koi faida nahi. Validation add karo ya seriously socho ki field ko public rakhne se problem hai?if (account.getBalance() > amount) account.setBalance(account.getBalance() - amount) — ye bahar se karna WRONG hai. account.withdraw(amount) — logic class ke andar hona chahiye!