Access Modifiers

public, private, protected, default

Interview Relevant: Scope and visibility questions
6 min read

Access Modifiers in Java

Access modifiers control the visibility and accessibility of classes, methods, and fields. Java has four levels of access.

Access Levels (Most to Least Restrictive)

Modifier Class Package Subclass World
private
(default)
protected
public

🔑 Best Practice: Start with most restrictive (private) and only increase access as needed. This is the principle of least privilege.

💡 Note: Top-level classes can only be public or default. private and protected are only for members.

Code Examples

private modifier - most restrictive

java
1// private - Only accessible within the same class
2public class BankAccount {
3    private double balance;          // Only this class can access
4    private String accountNumber;
5    
6    public BankAccount(String accountNumber) {
7        this.accountNumber = accountNumber;
8        this.balance = 0;
9    }
10    
11    // Private helper method
12    private boolean isValidAmount(double amount) {
13        return amount > 0;
14    }
15    
16    public void deposit(double amount) {
17        if (isValidAmount(amount)) {  // Can call private method
18            balance += amount;         // Can access private field
19        }
20    }
21    
22    public double getBalance() {
23        return balance;  // Controlled access via getter
24    }
25}
26
27// Outside the class:
28BankAccount acc = new BankAccount("123");
29// acc.balance = 1000000;        // ERROR! private
30// acc.isValidAmount(100);       // ERROR! private
31acc.deposit(100);                // OK - public method
32acc.getBalance();                // OK - public method

default (package-private) access

java
1// default (package-private) - No modifier keyword
2// File: com/myapp/User.java
3package com.myapp;
4
5class User {              // default class - package access only
6    String name;          // default field
7    int age;
8    
9    void display() {      // default method
10        System.out.println(name + ", " + age);
11    }
12}
13
14// File: com/myapp/UserManager.java
15package com.myapp;
16
17public class UserManager {
18    public void createUser() {
19        User user = new User();   // OK - same package
20        user.name = "Alice";      // OK - same package
21        user.display();           // OK - same package
22    }
23}
24
25// File: com/other/External.java
26package com.other;
27import com.myapp.*;
28
29public class External {
30    public void test() {
31        // User user = new User();   // ERROR! User class not visible
32        UserManager um = new UserManager(); // OK - public class
33    }
34}

protected modifier for inheritance

java
1// protected - Package + Subclass access
2package com.animals;
3
4public class Animal {
5    protected String name;        // Accessible in subclasses
6    protected int age;
7    
8    protected void makeSound() {  // Accessible in subclasses
9        System.out.println("Some sound");
10    }
11}
12
13// Same package - full access
14package com.animals;
15
16public class Zoo {
17    public void test() {
18        Animal a = new Animal();
19        a.name = "Leo";         // OK - same package
20        a.makeSound();          // OK - same package
21    }
22}
23
24// Different package, but subclass - limited access
25package com.pets;
26import com.animals.Animal;
27
28public class Dog extends Animal {
29    public void bark() {
30        name = "Buddy";         // OK - inherited protected
31        makeSound();            // OK - inherited protected
32        
33        // But NOT through another instance!
34        Animal other = new Animal();
35        // other.name = "X";    // ERROR! Not via different instance
36    }
37}

Complete example with all modifiers

java
1// public - Accessible from everywhere
2public class PublicAPI {
3    public static final String VERSION = "1.0";
4    
5    public String publicField;
6    
7    public PublicAPI() { }
8    
9    public void publicMethod() {
10        System.out.println("Anyone can call this");
11    }
12}
13
14// Complete Example - Encapsulation Best Practices
15public class Employee {
16    // Private fields - hide internal state
17    private int id;
18    private String name;
19    private double salary;
20    
21    // Public constructor - allow creation
22    public Employee(int id, String name) {
23        this.id = id;
24        this.name = name;
25        this.salary = 0;
26    }
27    
28    // Public getters - read access
29    public int getId() { return id; }
30    public String getName() { return name; }
31    public double getSalary() { return salary; }
32    
33    // Public setter with validation
34    public void setSalary(double salary) {
35        if (salary >= 0) {
36            this.salary = salary;
37        }
38    }
39    
40    // Private helper - internal use only
41    private void log(String message) {
42        System.out.println("[Employee " + id + "] " + message);
43    }
44    
45    // Protected method - for subclasses
46    protected void updateRecord() {
47        log("Record updated");
48    }
49}

Use Cases

  • Encapsulation - hiding implementation details
  • API design - controlling public interface
  • Inheritance - sharing with subclasses
  • Package organization - related class access
  • Security - protecting sensitive data
  • Maintainability - limiting change impact

Common Mistakes to Avoid

  • Making everything public
  • Using protected when private would work
  • Forgetting about default access
  • Protected != subclass-only
  • Exposing internal state unnecessarily
  • Not understanding package boundaries