Chapter 41 of 57

Access Modifiers in Java

As we work with classes and objects, we don't always want every variable and method to be accessible from everywhere in our program.

For example, if a BankAccount class has a balance variable, we probably don't want any other class to freely change it.

Java provides access modifiers to control where classes, variables, methods, and constructors can be accessed.

There are four main access levels you'll come across:

  • public

  • private

  • protected

  • default (when no modifier is written)

public

The public modifier means the member can be accessed from anywhere where the class itself is accessible.

For example:

class Student {
    public String name;
}

We can access name from another class:

Student student = new Student();

student.name = "John";

System.out.println(student.name);

Output:

John

Because name is public, other classes can access it directly.

You have already seen public in:

public static void main(String[] args)

Here, public allows the main() method to be accessible to the Java runtime.

private

The private modifier is the most restrictive access level.

A private member can only be accessed inside the same class.

For example:

class Student {
    private String name;

    void setName(String name) {
        this.name = name;
    }

    void showName() {
        System.out.println(name);
    }
}

We can access name inside Student, but we cannot directly access it from another class:

Student student = new Student();

student.name = "John"; // Error

Because name is private.

Instead, we can provide a method:

student.setName("John");

This is commonly used with encapsulation to protect important data.

protected

The protected modifier allows access:

  • Inside the same class

  • From classes in the same package

  • From subclasses, even when the subclass is in another package

For example:

class Animal {
    protected String name;
}

A child class can access it:

class Dog extends Animal {

    void showName() {
        System.out.println(name);
    }
}

Here, Dog inherits from Animal, so it can access the protected name.

protected is especially useful when designing classes that are intended to be extended by child classes.

Default Access

There is also a package-level access level that is used when we don't write any access modifier.

For example:

class Student {
    String name;
}

Here, name has default access.

It can be accessed by classes in the same package, but not by unrelated classes in other packages.

For example, if both classes are inside the school package:

package school;

class Student {
    String name;
}

another class in the same package can access name.

But a class in a different package cannot directly access it.

Access Modifier Comparison

The easiest way to understand the four levels is with this table:

Modifier

Same Class

Same Package

Subclass

Other Packages

public

Yes

Yes

Yes

Yes

protected

Yes

Yes

Yes

Yes*

default

Yes

Yes

No*

No

private

Yes

No

No

No

The * cases have an important detail: protected access from another package is available through inheritance, while default access does not extend to subclasses in other packages.

Access Modifiers with Classes

Access modifiers can also be used with classes.

For example:

public class Student {
}

A public top-level class can be accessed from other packages if imported.

A top-level class can also have no modifier:

class Student {
}

This gives it default/package-level access, meaning it can only be accessed from the same package.

A top-level class cannot be declared private or protected.

A Real-World Example

Let's imagine a BankAccount class:

class BankAccount {

    private double balance;

    public void deposit(double amount) {
        if (amount > 0) {
            balance += amount;
        }
    }

    public double getBalance() {
        return balance;
    }
}

Here, balance is private because we don't want outside code directly changing it.

But deposit() and getBalance() are public because we want other parts of the application to interact with the account through controlled methods.

For example:

BankAccount account = new BankAccount();

account.deposit(1000);

System.out.println(account.getBalance());

Output:

1000.0

This is a practical example of using access modifiers together with encapsulation.

Which Modifier Should You Use?

As a beginner, a good general approach is to give members the smallest access level they actually need.

For example, if a variable should only be used inside its class, make it private.

If a method needs to be available to other classes, it may be public.

If something is specifically intended to be available to subclasses, protected may be appropriate.

Avoid making everything public just because it's convenient. Restricting access helps keep your classes safer and easier to maintain.

The main idea to remember is:

Access modifiers control who can access a class or its members.

public gives broad access, private keeps things inside the class, protected is useful for inheritance and package access, and default access keeps things within the package.