Java

Explain Java Access Modifiers and Their Effect on Encapsulation

By Utility Zone · 2025-11-06T09:37:14.73085

Access modifiers are keywords in Java that specify the visibility and accessibility of classes, methods, constructors, and variables. They work in conjunction with encapsulation—a fundamental OOP principle—to control how data is accessed and modified, ensuring data integrity and preventing unauthorized access.123456

Comprehensive comparison of Java access modifiers and their accessibility scopes

Comprehensive comparison of Java access modifiers and their accessibility scopes


Understanding Encapsulation

Encapsulation is the bundling of data (variables) and methods that operate on that data into a single unit (class), while hiding the internal implementation details from the outside world. It's often called "data hiding" and is achieved using access modifiers.267

Real-World Analogy

Think of encapsulation like a capsule medicine. The active ingredient is hidden inside, protected from the outside environment. You don't need to know how the medicine is made; you only care about what it does when you take it. Similarly, in Java, the internal details of a class are hidden, and you interact with it only through well-defined public methods.6


The Four Access Modifiers

Java provides four access modifiers, ordered from most restrictive to most permissive:135

1. private (Most Restrictive)

The private modifier provides the highest level of restriction.58

Characteristics:85

  • Accessible only within the same class58
  • Cannot be accessed from other classes, even subclasses5
  • Cannot be applied to top-level classes5
  • Used for: Methods, constructors, and variables that should never be accessed from outside the class8

Syntax:

private int age;
private void internalMethod() { }

Example:5

class A {
    private int value = 40;
    
    private void show() {
        System.out.println("Private method called");
    }
}

public class Main {
    public static void main(String[] args) {
        A obj = new A();
        System.out.println(obj.value);  // Compilation Error: 'value' has private access
        obj.show();                      // Compilation Error: 'show()' has private access
    }
}

When to Use:98

  • Hide implementation details and internal state
  • Prevent accidental modification of critical data
  • Create immutable classes (with final keyword)
  • Implement singleton patterns with private constructors

2. default (Package-Private) (No Keyword Required)

When no access modifier is specified, the default (package-private) modifier is applied.135

Characteristics:35

  • Accessible within the same package only53
  • Acts as public within the package and private outside the package5
  • Cannot be accessed from classes in different packages35
  • Can be applied to both classes and members5

Example:5

// File: A.java
package p1;

class A {  // default access - no modifier
    void show() {
        System.out.println("p1");
    }
}
// File: B.java
package p2;

import p1.*;

class B {
    public static void main(String[] args) {
        A ob = new A();      // Compilation Error: 'A' is not public
        ob.show();           // Error
    }
}

When to Use:3

  • For utility classes used only within a package
  • When you want package-level encapsulation
  • Deliberate package-wide access

3. protected

The protected modifier allows access within the package and to subclasses outside the package.51011

Characteristics:1011

  • Accessible within the same package1110
  • Accessible to subclasses outside the package1011
  • Cannot access from non-child classes outside the package10
  • Cannot be applied to top-level classes10
  • Used primarily with inheritance1110

Example:5

// File: A.java
package p1;

public class A {
    protected void m1() {
        System.out.println("Protected method in p1");
    }
}
// File: B.java
package p2;

import p1.*;

class B extends A {  // B is a subclass of A
    public static void main(String[] args) {
        B ob = new B();
        ob.m1();  // Works! Can access protected method through subclass
        System.out.println("p1");
    }
}

Output: Protected method in p1

When to Use:1110

  • Methods or fields that should be accessible to subclasses
  • Creating extension points for inheritance
  • Sharing implementation details with subclasses while hiding from unrelated classes

4. public (Least Restrictive)

The public modifier provides unrestricted access.510

Characteristics:105

  • Accessible from anywhere (same class, same package, different packages)10
  • Can be applied to classes, methods, constructors, and variables10
  • Most open level of access10

Example:5

// File: A.java
package pack1;

public class A {
    public void m1() {
        System.out.println("GFG");
    }
}
// File: B.java
package pack2;

import pack1.A;

class B {
    public static void main(String[] args) {
        A a = new A();
        a.m1();  // Works! Can access public method from different package
    }
}

Output: GFG

When to Use:10

  • Methods that form the public API of your class
  • Classes that should be accessible from anywhere
  • Use sparingly—it breaks encapsulation

Access Modifier Accessibility Matrix

Contextprivatedefault (package)protectedpublic
Same Class✓✓✓✓
Same Package (non-subclass)✗✓✓✓
Different Package (subclass)✗✗✓✓
Different Package (non-subclass)✗✗✗✓

Access Modifiers in Inheritance

Access modifiers behave differently when dealing with inheritance:121113

Private Members:11

  • NOT inherited by subclasses
  • Only accessible within the class they're defined in
  • Subclasses cannot access or override them
class Parent {
    private int x = 30;  // Not inherited
    
    private void m1() {
        System.out.println("Private method");
    }
}

class Child extends Parent {
    // x and m1() are NOT available here
    // This will not compile: System.out.println(x);
}

Default Members:11

  • Inherited by subclasses only within the same package
  • Cannot be accessed by subclasses in different packages
package inheritance;

class Parent {
    int x = 30;  // Default access
    
    void m1() {
        System.out.println("Default method");
    }
}

class Child extends Parent {
    void display() {
        System.out.println(x);  // Works - within same package
        m1();                   // Works - within same package
    }
}

Protected Members:1211

  • Inherited by all subclasses
  • Accessible within the package by any class
  • Accessible outside the package only through subclass reference
package inheritance;

public class Parent {
    protected int y = 50;
    
    protected void m2() {
        System.out.println("Parent protected method");
    }
}

public class Child extends Parent {
    void display() {
        System.out.println(y);  // Works - can access inherited protected member
        m2();                   // Works
    }
}

Public Members:11

  • Inherited by all subclasses
  • Accessible everywhere

Encapsulation: Putting It All Together

Encapsulation combines private access modifiers with public getter and setter methods to control data access.24147

Implementation Steps

  1. Make fields private67
  2. Provide public getter methods to read values76
  3. Provide public setter methods to modify values with validation67
  4. Add validation logic in setters to ensure data integrity6

Basic Encapsulation Example:2414

public class Person {
    // Step 1: Make fields private
    private String name;
    private int age;
    
    // Step 2: Provide getter methods
    public String getName() {
        return name;
    }
    
    public int getAge() {
        return age;
    }
    
    // Step 3: Provide setter methods with validation
    public void setName(String name) {
        if (name != null && !name.isEmpty()) {
            this.name = name;
        }
    }
    
    public void setAge(int age) {
        if (age > 0 && age < 150) {  // Validation
            this.age = age;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        
        // Using setter methods
        person.setName("John");
        person.setAge(30);
        
        // Using getter methods
        System.out.println("Name: " + person.getName());  // Output: Name: John
        System.out.println("Age: " + person.getAge());    // Output: Age: 30
    }
}

Encapsulation with Validation:6

public class BankAccount {
    private double balance;
    
    // Getter - only read access
    public double getBalance() {
        return balance;
    }
    
    // Setter with validation - prevents invalid operations
    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
            System.out.println("Deposited: " + amount);
        } else {
            System.out.println("Invalid deposit amount");
        }
    }
    
    public void withdraw(double amount) {
        if (amount > 0 && amount <= balance) {
            balance -= amount;
            System.out.println("Withdrawn: " + amount);
        } else {
            System.out.println("Invalid withdrawal amount or insufficient balance");
        }
    }
}

public class Main {
    public static void main(String[] args) {
        BankAccount account = new BankAccount();
        account.deposit(1000);      // Deposited: 1000
        account.withdraw(500);      // Withdrawn: 500
        account.withdraw(1000);     // Invalid withdrawal amount or insufficient balance
        System.out.println("Balance: " + account.getBalance());  // Balance: 500.0
    }
}

Benefits of Encapsulation with Access Modifiers

  1. Data Hiding:15166
    • Internal implementation details remain hidden from external code
    • Reduces complexity for users of the class
  2. Increased Flexibility:16615
    • Change internal implementation without affecting external code
    • Add validation or side effects without breaking the API
  3. Controlled Access:867
    • Prevent unauthorized or invalid modifications
    • Ensure data consistency and integrity
  4. Improved Maintainability:1516
    • Well-defined public interface makes code easier to understand
    • Easier to refactor internal implementation
  5. Reusability:615
    • Encapsulated classes are more reliable and easier to reuse
  6. Testing:1615
    • Easier to unit test encapsulated classes through public methods

Best Practices for Access Modifiers and Encapsulation

  1. Use the Principle of Least Privilege:179
    • Start with the most restrictive modifier (private)
    • Only increase visibility when necessary
    • Most fields should be private17
  2. Make Fields Private:9617
    • Never expose fields directly
    • Provide getters/setters for controlled access6
  3. Provide Meaningful Getter/Setter Methods:46
    • Use descriptive names (getName(), setAge())
    • Include validation in setters
  4. Use Final for Immutability:89
private final int accountNumber = 123;
  1. Never Use Public Fields:917
    • Bad: public String name;
    • Good: private String name; with public String getName()
  2. Consider Protected for Extension Points:1012
    • Use protected for methods subclasses should override
  3. Document Your API:17
    • Clear public interface communicates what's safe to use

Real-World Example: Student Class

public class Student {
    // Private fields - hidden from outside
    private String studentId;
    private String name;
    private double gpa;
    private int creditsCompleted;
    
    // Constructor
    public Student(String studentId, String name) {
        this.studentId = studentId;
        this.name = name;
        this.gpa = 0.0;
        this.creditsCompleted = 0;
    }
    
    // Getters
    public String getStudentId() {
        return studentId;  // Student ID should not change
    }
    
    public String getName() {
        return name;
    }
    
    public double getGPA() {
        return gpa;
    }
    
    public int getCreditsCompleted() {
        return creditsCompleted;
    }
    
    // Setters with validation
    public void setName(String name) {
        if (name != null && !name.trim().isEmpty()) {
            this.name = name;
        }
    }
    
    public void updateGPA(double newGPA) {
        if (newGPA >= 0.0 && newGPA <= 4.0) {
            this.gpa = newGPA;
        } else {
            throw new IllegalArgumentException("GPA must be between 0.0 and 4.0");
        }
    }
    
    public void addCredits(int credits) {
        if (credits > 0) {
            creditsCompleted += credits;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        Student student = new Student("S12345", "Alice");
        student.setName("Alice Johnson");
        student.updateGPA(3.8);
        student.addCredits(12);
        
        System.out.println("ID: " + student.getStudentId());
        System.out.println("Name: " + student.getName());
        System.out.println("GPA: " + student.getGPA());
        System.out.println("Credits: " + student.getCreditsCompleted());
    }
}

Understanding access modifiers and encapsulation is essential for writing secure, maintainable, and professional-quality Java code. They form the foundation of data protection and code organization in object-oriented programming.126 <span style="display:none">1819</span>


<div align="center">⁂</div>

Footnotes

  1. https://idratherbewriting.com/java-access-modifiers/ ↩ ↩2 ↩3 ↩4

  2. https://www.geekster.in/articles/encapsulation-in-java/ ↩ ↩2 ↩3 ↩4 ↩5

  3. https://www.geekster.in/articles/java-access-modifiers/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  4. https://www.simplilearn.com/tutorials/java-tutorial/java-encapsulation ↩ ↩2 ↩3 ↩4

  5. https://onecompiler.com/tutorials/java/more/access-modifiers ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 ↩17 ↩18 ↩19 ↩20

  6. https://www.datacamp.com/doc/java/encapsulation ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16

  7. https://www.geeksforgeeks.org/java/encapsulation-in-java/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6

  8. https://www.datacamp.com/doc/java/private ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7

  9. https://www.crio.do/blog/encapsulation-in-java/ ↩ ↩2 ↩3 ↩4 ↩5

  10. https://www.geeksforgeeks.org/java/public-vs-protected-vs-package-vs-private-access-modifier-in-java/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15

  11. https://www.scientecheasy.com/2019/11/access-modifiers-in-inheritance.html/ ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11

  12. https://codefinity.com/courses/v2/7e5aa9aa-cc31-4221-8c3c-17e302f66dfd/7ee034e6-5d3a-462b-9f4f-f61f68f66eae/5524ea6b-1d03-4a5e-a5df-9c7e0fa2246e ↩ ↩2 ↩3

  13. https://www.slideshare.net/slideshow/access-modifier-and-inheritance/81458780 ↩

  14. https://www.w3resource.com/java-exercises/encapsulation/java-encapsulation-exercise-2.php ↩ ↩2

  15. https://www.linkedin.com/pulse/what-advantages-encapsulation-java-kapil-sharma-irdcc ↩ ↩2 ↩3 ↩4 ↩5

  16. https://intellipaat.com/blog/java-encapsulation/ ↩ ↩2 ↩3 ↩4

  17. https://www.linkedin.com/pulse/scope-access-modifiers-java-lalitha-bourishetty ↩ ↩2 ↩3 ↩4 ↩5

  18. https://www.slideshare.net/slideshow/access-modifiers-in-java-239503172/239503172 ↩

  19. https://sentry.io/answers/what-is-the-difference-between-public-protected-package-private-and-private-in-java/ ↩