Access Modifiers in Java

Caner Ünal
Codimis
Published in
4 min readJul 24, 2023
Photo by Sigmund on Unsplash

In Java, access modifiers play a crucial role in controlling the visibility and accessibility of classes, methods, and variables. They are an essential part of object-oriented programming (OOP) principles, enabling encapsulation, data hiding, and modularity in Java applications. There are four types of access modifiers in Java: private, public, default (package-private), and protected. Each modifier has specific rules governing the scope and accessibility of elements within a Java program.

In this article, we will dive into the concept of access modifiers in Java, explore each type in detail, provide example code for different use cases, and finally understand how access modifiers align with the principles of object-oriented programming.

Access Modifiers with Examples

Private

When an element is marked as private, it becomes accessible only within the class where it is declared. No other class, even those in the same package or subclasses, can access this element directly.

It is often used to hide implementation details and maintain data encapsulation, preventing direct access and modification from outside the class. By using getter and setter methods, we can provide controlled access to private variables.

public class BankAccount {
private double balance;

public BankAccount(double initialBalance) {
this.balance = initialBalance;
}

// Getter method to access the private balance
public double getBalance() {
return balance;
}

// Method to withdraw funds
public void withdraw(double amount) {
if (amount > 0 && amount <= balance) {
balance -= amount;
}
}
}

In the above example, the balance variable is marked as private, ensuring that it can only be accessed and modified through the getBalance() and withdraw() methods, enforcing proper encapsulation.

Public

Elements marked as public are accessible from any part of the program, regardless of the package or class. They have the widest scope and can be accessed without any restrictions.

This modifier is commonly used for methods and variables that should be accessible to all parts of the program.

public class MathUtils {
public static final double PI = 3.14159;

public static int add(int a, int b) {
return a + b;
}
}

In this example, the PI constant and the add() method are marked as public, allowing other classes to access them directly without any restrictions.

Default (package-private)

If no access modifier is explicitly specified, the element is considered to have default access. Therefore, this can also be called a no modifier. This means it is accessible within the same package but not from classes outside the package.

package com.example.calculator;
class BasicCalculator {
int add(int a, int b) {
return a + b;
}
}

In this scenario, the add() method is given default access because no access modifier is specified. This means it can be accessed by other classes within the same package, but not from outside the package.

Protected

Elements with the protected modifier can be accessed within the same package and by subclasses, even if they are in a different package.

It is commonly used when certain components need to be accessible to subclasses while still limiting access from unrelated classes.

package com.example.animals;

public class Animal {
protected String name;

protected void makeSound() {
System.out.println("Animal makes a sound");
}
}

In this example, the name variable and the makeSound() method are marked as protected, making them accessible within the same package and by subclasses of the Animal class, even if the subclasses are in a different package.

Difference between default and protected

You may notice the slight difference between protected and default access modifier. Let’s elaborate this by extending the examples below again.

Let’s define a class which name is Bird. Bird class extends Animal, and stays in a different package (com.example.bird) from Animal class. I can still access makeSound() method of Animal and it can be called like below. This example proves that subclasses can still access protected methods, even if they are placed in a different package.

package com.example.bird;

import com.example.animals.Animal;

public class Bird extends Animal {

public void getBirdSound(){
this.makeSound();
}
}

Now, I will try to access default class and method of BasicCalculator class from a different package. I create a new package which name is com.example.averagecalculator, and put AverageCalculator class in that package. When I try to create a new instance for BasicCalculator class, the compiler shows me a warning.

‘com.example.calculator.BasicCalculator’ is not public in ‘com.example.calculator’. Cannot be accessed from outside package.

package com.example.averagecalculator;

import com.example.calculator.BasicCalculator;

public class AverageCalculator {

public int calculateAverage(int a, int b){
BasicCalculator basicCalculator = new BasicCalculator();
}
}

I am changing to modifier of BasicCalculator to public, the class is accessible from everywhere now. I want to call add() method of BasicCalculator. However, add() method is still has default modifier. Therefore, I will get the same warning above for the calling add() method of BasicCalculator.

package com.example.averagecalculator;

import com.example.calculator.BasicCalculator;

public class AverageCalculator {

public int calculateAverage(int a, int b){
BasicCalculator basicCalculator = new BasicCalculator();
return basicCalculator.add(a,b)/2;
}
}

Access modifiers in Java are a fundamental aspect of object-oriented programming that enable developers to control the visibility and accessibility of classes, methods, and variables. Understanding the differences between private, public, default, and protected access modifiers is essential for creating well-structured, secure, and maintainable Java applications.

By following the principles of encapsulation, inheritance, and modularity, developers can make the most of access modifiers to design efficient and robust software systems. Mastering access modifiers empowers Java developers to build scalable and extensible applications while maintaining data integrity and security.

--

--