Access Modifiers in Java

Access modifiers are a crucial aspect of Java's object-oriented programming paradigm, providing a way to control the visibility and accessibility of classes, methods, and fields within a program. They are also known as visibility modifiers.In this tutorial we will learn about various access modifiers like private, public, default and protected and their effect on the scope and accessibility.

Access level modifiers for member field and methods determine whether other classes can use a particular field or call a particular method.

Java supports four member access modifiers
  • public : Accessible from any other class.

  • protected : Accessible within the same package and by subclasses.

  • default(no modifier) : Accessible within the same package.

  • private : Accessible only within the same class.

Why Use Access Modifiers?

Access modifiers play a crucial role in designing robust and maintainable code. They provide a way to implement encapsulation, control visibility, and manage the complexity of large codebases. By carefully choosing access modifiers, developers can expose only the necessary parts of their code, reducing the chances of unintended interference and promoting modular and scalable software design.


Private Access Modifier

Private members are accessible only with in the same class. Private access modifier is the most restrictive of all access level. Private variables, methods and constructors can only be accessed in its own class not even from classes in same package.

  • keyword "private" is used of private access modifier.

  • Class and interfaces cannot be private.

  • Private access modifier helps to encapsulate your variables and methods which you want to hide from rest of the world.

  • Private members can be accessed by other classes, if class provides a public getter method.

Here is an example of restricting access to a member variable using private access modifier.

package com.tcc.java.tutorial;

class BankAccount {
    private long accountNumber;
}

public class PrivateAccessModifier {
    public static void main(String[] args) {
        // Create an object of BankAccount class
        BankAccount account = new BankAccount();

        // Access private field accountNumber
        account.accountNumber = 76537527;
    }
}
Output
Error:(13, 16) java: accountNumber has private access in
com.tcc.java.tutorial.BankAccount

In above program, we have declared a class called "BankAccount" which contans a private member variable accountNumber. Variable accountNumber cannot be accessed directly using dot operation from any other class. Due to which we are getting a compile time error for private member access.

We can define public read and write methods inside BankAccount class to access the private variable from outside BankAccount class.

package com.tcc.java.tutorial;

class BankAccount {
    // Private field
    private long accountNumber;

    // Public methods
    public void setAccountNumber(long number) {
        accountNumber = number;
    }

    public long getAccountNumber() {
        return accountNumber;
    }
}

public class PrivateAccessModifier {
    public static void main(String[] args) {
        // Create an object of BankAccount class
        BankAccount account = new BankAccount();

        // Access private field accountNumber
        account.setAccountNumber(76537527);
        System.out.println(account.getAccountNumber());
    }
}
Output
76537527

Public Access Modifier

Public classes, interfaces, member variables, member methods and constructors are accessible everywhere. This is the least restrictive of all access modifiers.

  • Keyword "public" is used for public access modifiers.

  • Public is also a top level access modifier. It means not only member variables and methods, we can attach public access modifiers with classes and interfaces.

  • Generally, common routines and variables, utility methods that need to be accessed from everywhere are declared public.

  • All public variables and methods of a super class are inherited by its subclasses.

Here is an example of public access to a member variables and methods using public access modifier.

class Student {
    public String name;
    public int age;

    public void printStudentDetails(){
        System.out.println("I am " + name);
        System.out.println("I am " + age +
                " years old");
    }
}

public class PublicAccessModifier {
    public static void main(String[] args) {
        Student john = new Student();
        john.name = "John Jackson";
        john.age = 15;

        john.printStudentDetails();
    }
}
Output
I am John Jackson
I am 15 years old

In above program, we have declared a class called "Student" which contans a public method printStudentDetails and two public member variable name and age. We created an object of class Student called "john". Using dot opertaor, we are accessing member variable and method from other class.


Protected Access Modifier

Protected member variables, methods and constructors can only be accessed from it's own class, classes of same package and subclasses in other packages. Outside of it's own package, the scope of protected members are limited to only subclasses.

  • Keyword "protected" is used for protected access modifiers.

  • Class and interfaces cannot be protected.

  • Methods and fields of interfaces cannot be declared as protected.

  • Unlike public access modifier, protected have limited visibility outside of it's package. Protected variables and methods are used when we want to restrict it's access from all classes outside of my package except sub-classes.

Here is an example of protected access to a member method fly using protected keyword.

class Bird {
    protected void fly() {
        System.out.println("Bird is flying");
    }
}

public class Eagle extends Bird {
    public static void main(String[] args) {
        // Creating an object of Eagle
        Eagle eagle1 = new Eagle();
        // Accessing protected method
        eagle1.fly();
    }
}
Output
Bird is flying

In above program, we have declared a class called "Bird" which contans a protected method fly. Subclass Eagle inherits from class Bird. We created an object of class Eagle called "eagle1". Because fly method of Bird class is protected, subclass Eagle can access it using dot opertaor from it's main method.


Default Access Modifier

When we don't specify any access modifiers then default access modifier is used. The accessibility of default members are limited to classes in their own package. Any class out side of their own package cannot access default member variables and member methods.

Default access modifier is similar to protected except even subclasses outside of our own package cannot access it.


The following table shows the access to members permitted by each modifier.
Modifier Class Package Subclass World
public YES YES YES YES
protected YES YES YES NO
default(no modifier) YES YES NO NO
private YES NO NO NO
How to choose an access level?
  • If your objects stores some critical data which you don't want to share with any other class(not even with subclasses) then make your member variables private.

  • If you want to expose your private member variable to rest of the world then create a public getter function.

  • If you want to restrict access to a member variable but still want to share it with your subclasses, then make it protected.

  • If your object is not dealing with any critical data then make your member variables and methods public Or alternatively you can provide public getters.


Best Practices for Using Access Modifiers

  • Minimize Visibility : Minimize the visibility of classes, methods, and fields by using the most restrictive access modifier that still allows the necessary functionality. This promotes encapsulation and reduces the chance of unintended interference.

  • Encapsulation : Encapsulate the internal state of a class by keeping fields private and providing controlled access through getter and setter methods. This allows for better control over the class's internal state and ensures data consistency.

  • Think About API Design : When designing APIs, carefully choose access modifiers for classes, methods, and fields. Public elements form the API surface and should be well-documented. Internal implementation details should have restricted access to avoid unnecessary exposure.

  • Favor Composition Over Inheritance : While inheritance can be powerful, favor composition over inheritance to achieve code reuse and maintainability. Using access modifiers effectively in a composition-based design can lead to a more modular and extensible codebase.

  • Follow Naming Conventions : Follow naming conventions to make your code more readable. Use meaningful names for classes, methods, and fields to convey their purpose. This becomes especially important when elements have package-private or default access.

Conclusion

Access modifiers in Java provide a powerful mechanism for controlling the visibility and accessibility of classes, methods, and fields. By understanding and applying the principles of encapsulation and information hiding, developers can create more maintainable, modular, and scalable code. Whether you are working on small projects or large-scale applications, mastering access modifiers is a fundamental skill for Java developers, contributing to the creation of robust and well-designed software systems