Encapsulation and Variable Scopes in Java

Master encapsulation, variable scopes, immutable objects, and local variable type inference (var keyword) for the OCP 21 exam.

Table of Contents

1. Encapsulation

Encapsulation is one of the four fundamental OOP principles. It bundles data (fields) and methods that operate on that data together, and restricts direct access to internal implementation details.

1.1 Benefits of Encapsulation

  • Data Protection: Prevents unauthorized access to internal data
  • Controlled Access: Provides controlled access through methods
  • Flexibility: Allows changing internal implementation without affecting clients
  • Validation: Enables data validation before setting values
  • Maintainability: Makes code easier to maintain and modify

1.2 Encapsulation Example

Example:
// Poor encapsulation (public fields) class BadPerson {
    public String name;
    public int age;
    // Can be set to negative! } // Good encapsulation (private fields with accessors) class Person {
    private String name;
    private int age;
    // Controlled access through methods public String getName() {
        return name;
    }
public void setName(String name) {
    if (name != null && !name.isEmpty()) {
        this.name = name;
    }
} public int getAge() {
return age;
}
public void setAge(int age) {
    if (age >= 0) {
        // Validation this.age = age;
    }
else {
    throw new IllegalArgumentException("Age cannot be negative");
}
} }

2. Access Modifiers

Access modifiers control the visibility and accessibility of classes, fields, and methods.

2.1 Access Modifier Levels

Modifier Class Package Subclass World
private
(package-private)
protected
public

2.2 Examples

Example:
class Example {
    private int privateField;
    // Only within class int packageField;
    // Package-private (default) protected int protectedField;
    // Package + subclasses public int publicField;
    // Everywhere private void privateMethod() {
    }
void packageMethod() {
}
protected void protectedMethod() {
}
public void publicMethod() {
}
}

3. Getters and Setters

Getters and setters provide controlled access to private fields.

3.1 Standard Getters and Setters

Example:
class Person {
    private String name;
    private int age;
    // Getter (accessor) public String getName() {
        return name;
    } // Setter (mutator) public void setName(String name) {
    this.name = name;
} // Getter for primitive public int getAge() {
return age;
} // Setter with validation public void setAge(int age) {
if (age < 0) {
    throw new IllegalArgumentException("Age cannot be negative");
}
this.age = age;
}
} Person person = new Person();
person.setName("Alice");
person.setAge(30);
System.out.println(person.getName());
// Alice System.out.println(person.getAge());
// 30

3.2 Read-Only and Write-Only Fields

Example:
class Account {
    private String accountNumber;
    private double balance;
    // Read-only (no setter) public String getAccountNumber() {
        return accountNumber;
    } // Read-only balance (can only be modified internally) public double getBalance() {
    return balance;
} // Controlled modification through methods public void deposit(double amount) {
if (amount > 0) {
    balance += amount;
}
} public boolean withdraw(double amount) {
if (amount > 0 && amount <= balance) {
    balance -= amount;
    return true;
}
return false;
}
}

4. Variable Scopes

Variable scope determines where a variable can be accessed. Java has several types of variable scopes.

4.1 Instance Variable Scope

Example:
class Person {
    private String name;
    // Instance variable - accessible throughout class void method1() {
        name ="Alice";
        // Can access }
    void method2() {
        System.out.println(name);
        // Can access }
}

4.2 Static Variable Scope

Example:
class Counter {
    static int count = 0;
    // Static variable - accessible throughout class void increment() {
        count++;
        // Can access }
    static void display() {
        System.out.println(count);
        // Can access }
}

4.3 Local Variable Scope

Example:
class Example {
    void method() {
        int localVar = 10;
        // Local variable - scope is method if (true) {
            int blockVar = 20;
            // Block-scoped variable System.out.println(localVar);
            // Can access localVar System.out.println(blockVar);
            // Can access blockVar } // System.out.println(blockVar);
        // Error - out of scope System.out.println(localVar);
        // OK - still in scope }
    void anotherMethod() {
        // System.out.println(localVar);
        // Error - different method }
}

4.4 Scope Rules

  • Variables are accessible from their declaration point to the end of their scope
  • Local variables shadow instance/static variables with the same name
  • Block-scoped variables (in if/for/while) are only accessible within that block
  • Cannot redeclare a variable in the same scope
Example:
class Example {
    int value = 10;
    // Instance variable void method() {
        int value = 20;
        // Local variable shadows instance variable System.out.println(value);
        // 20 (local) System.out.println(this.value);
        // 10 (instance) for (int i = 0;
        i < 5;
        i++) {
            int loopVar = i;
            // Block-scoped } // System.out.println(loopVar);
        // Error - out of scope }
}

5. Immutable Objects

Immutable objects cannot be modified after creation. They are thread-safe and prevent accidental state changes.

5.1 Creating Immutable Classes

To create an immutable class:

  1. Make all fields final and private
  2. Don't provide setters
  3. Don't allow subclasses to override methods (make class final )
  4. Ensure mutable fields are not exposed directly
  5. Initialize all fields in constructor
Example:
// Immutable class final class ImmutablePerson {
    private final String name;
    private final int age;
    private final List<
    String>
    hobbies;
    // Mutable field public ImmutablePerson(String name, int age, List<
    String>
    hobbies) {
        this.name = name;
        this.age = age;
        // Defensive copy for mutable fields this.hobbies = new ArrayList<
        >
        (hobbies);
    }
public String getName() {
    return name;
}
public int getAge() {
    return age;
} // Return defensive copy, not original list public List<
String>
getHobbies() {
    return new ArrayList<
    >
    (hobbies);
} // No setters! } // Using immutable object List<
String>
hobbies = new ArrayList<
>
();
hobbies.add("Reading");
ImmutablePerson person = new ImmutablePerson("Alice", 30, hobbies);
hobbies.add("Swimming");
// Doesn't affect person's hobbies person.getHobbies().add("Coding");
// Doesn't affect original

    list

5.2 Records as Immutable Objects

Example:
// Records are immutable by default record Point(int x, int y) {
    // All fields are final // No setters generated // Can add validation in compact constructor public Point {
        if (x < 0 || y < 0) {
            throw new IllegalArgumentException("Coordinates must be non-negative");
        }
} }
Point p = new Point(10, 20);
// p.x = 30;
// Compilation error - fields are
final

6. Local Variable Type Inference (var)

The var keyword (Java 10+) allows the compiler to infer the type of a local variable from its initializer.

6.1 Using var

Example:
// Traditional declaration String name ="Alice";
int age = 30;
List<
String>
list = new ArrayList<
>
();
// Using var (type inferred) var name2 ="Alice";
// Inferred as String var age2 = 30;
// Inferred as int var list2 = new ArrayList<
String>
();
// Inferred as ArrayList<
String>
// var with method calls var result = Math.max(10, 20);
// Inferred as int var person = new Person("Bob", 25);
// Inferred as Person // var in loops for (var i = 0;
i < 10;
i++) {
    // Inferred as int System.out.println(i);
}
for (var item : list) {
    // Inferred from list element type System.out.println(item);
}

6.2 var Restrictions

  • Can only be used for local variables
  • Must have an initializer (cannot be null without type hint)
  • Cannot be used for method parameters
  • Cannot be used for return types
  • Cannot be used for fields
  • Cannot be used in catch blocks (Java 10-10), allowed in Java 11+
Invalid Uses:
// var name;
// Error - no initializer // var name = null;
// Error - cannot infer type from null // private var field;
// Error - cannot use for fields // public var method() {
} // Error - cannot use for return type // void method(var param) {
} // Error - cannot use for parameters // Valid null with explicit type hint var list = (List<
String>
) null;
// OK - type explicitly
provided

6.3 When to Use var

Best Practices:
  • Use when type is obvious from context
  • Use for complex generic types
  • Avoid when it reduces readability
  • Don't use for public APIs
Example:
// Good use - complex type var map = new HashMap<
String, List<
Map<
Integer, String>
>
>
();
// Good use - obvious from context var person = new Person("Alice", 30);
// Consider readability var result = calculateComplexValue();
// Type might not be obvious // Better: SpecificType result =
calculateComplexValue();

7. Exam Key Points

Critical Concepts for OCP 21 Exam:

  • Encapsulation: Bundling data and methods, restricting direct access
  • Access Modifiers: private, package-private, protected, public
  • private: Only accessible within the same class
  • protected: Accessible in package and subclasses
  • public: Accessible from anywhere
  • package-private: Default, accessible within same package
  • Getters: Methods to read field values
  • Setters: Methods to modify field values with validation
  • Instance Variable Scope: Accessible throughout the class
  • Static Variable Scope: Accessible throughout the class
  • Local Variable Scope: Accessible from declaration to end of block
  • Variable Shadowing: Local variables can shadow instance/static variables
  • this Keyword: Refers to current instance, used to access shadowed fields
  • Immutable Objects: Cannot be modified after creation
  • Immutable Requirements: final fields, no setters, final class, defensive copies
  • Records: Immutable by default, all fields are final
  • var Keyword: Local variable type inference (Java 10+)
  • var Restrictions: Only local variables, must have initializer, not for fields/methods
  • Defensive Copying: Create copies of mutable objects to prevent external modification

Post a Comment

0 Comments