Access specifiers in Java

  • Last Updated: March 10, 2025
  • By: javahandson
  • Series
img

Access specifiers in Java

Learn about Access Specifiers in Java – Private, Public, Protected, and Default. Understand their usage, differences, and best practices with examples.

 

Access specifiers in Java are keywords that define the visibility or scope of a class, method, or variable. They control which other classes or components can access a particular class member.

Importance of Access Specifiers

Encapsulation & Data Hiding

1. Restricts Direct Access: Prevents direct modification of sensitive data by using private members.
2. Encapsulates Implementation Details: Changes to internal logic don’t affect other parts of the program.
3. Provides Controlled Access: Getters and setters allow controlled modifications, ensuring data consistency.

Better Code Maintainability

1. Reduces Code Coupling: Restricts access to only necessary parts, making code changes easier.
2. It prevents unintended modifications and limits access to sensitive fields, reducing bugs.
3. Encourages a Clear API: Developers know what is intended for external use (public) and what is internal (private).

Enhanced Security

1. Prevents Unauthorized Access: private and protected restrict access to critical data and methods.
2 Minimizes Data Corruption: Controlled access ensures only valid operations modify data.
3. It encourages Secure Coding Practices and hides sensitive implementation details, reducing vulnerabilities.

Supports Inheritance & Code Reusability

1. Allows Controlled Inheritance: Protected methods and fields can be inherited without exposing them to external classes.
2. Facilitates Code Reuse: Subclasses can reuse existing logic without modifying base class internals.
3. Enables Method Overriding: Proper access control ensures overridden methods follow the intended behavior.

Avoids Naming Conflicts

1. Prevents Ambiguity: Restricts visibility of members, avoiding conflicts in large projects.
2. Encapsulates Implementation Details: Different classes can have the same variable names without interference.
3. Ensures Proper Access Scope: Methods and variables are accessible only where necessary, preventing clashes.

Promotes Modularity

1. Encourages the Separation of Concerns: Access specifiers define clear boundaries between components.
2. Enhances Readability: Developers can quickly understand what’s accessible and what’s internal.
3. Facilitates Unit Testing: Private methods keep internals hidden while exposing only necessary functionality for testing.

Types of Access Specifiers

Java provides four types of access specifiers:

Private – Accessible only within the same class.
Default (Package-private) – Accessible within the same package.
Protected – Accessible within the same package and subclasses in different packages.
Public – Accessible from anywhere in the program.

Private Access Specifier (private)

1. The most restrictive access specifier.
2. Members declared private are only accessible within the same class.
3. Other classes cannot access them, even those in the same package.

Common Use Case: Used for encapsulation, keeping fields and helper methods private.

package com.java.handson.access.specifiers.pkg1;

public class Student {
    private int rollNumber;
    String name;
    int marks;

    public Student(int rollNumber, String name, int marks) {
        this.rollNumber = rollNumber;
        this.name = name;
        this.marks = marks;
    }
    
    public int getRollNumber() {
        return rollNumber; // private variable can be accessed in the same class
    }
}

package com.java.handson.access.specifiers.pkg1;

public class Main {
    public static void main(String[] args) {
        Student student = new Student(101, "Suraj", 70);
        String name = student.name;
        int rollNumber = student.rollNumber; // Compilation Error 
    }
}
Output: java: rollNumber has private access in com.java.handson.access.specifiers.pkg1.Student

Default (Package-Private) Access Specifier

If no access specifier is mentioned, Java assigns default (package-private) access. Members with default access can be accessed within the same package but not from outside.

Common Use Case: Used when classes within the same package need access, but external classes should not.

package com.java.handson.access.specifiers.pkg1;

public class Main {
    public static void main(String[] args) {
        Student student = new Student(101, "Suraj", 70);
        String name = student.name;  // name is of default type hence it can be accessed in same package
        System.out.println("Name of student : " + name);
    }
}
Output: Name of student : Suraj
package com.java.handson.access.specifiers.pkg2;

import com.java.handson.access.specifiers.pkg1.Student;

public class Main {
    public static void main(String[] args) {
        Student student = new Student(101, "Suraj", 70);
        String name = student.name;  // Compilation Error 
        System.out.println("Name of student : " + name);
    }
}
Output: java: name is not public in com.java.handson.access.specifiers.pkg1.Student; cannot be accessed from outside package

Protected Access Specifier

Members declared protected are accessible:

  • Within the same package (like default access).
  • In subclasses (even in different packages) via inheritance.

Common Use Case: Used when a method/variable should be accessible to child classes but not to unrelated classes.

package com.java.handson.access.specifiers.pkg1;

public class Student {
    private int rollNumber;
    String name;
    protected int marks;

    public Student(int rollNumber, String name, int marks) {
        this.rollNumber = rollNumber;
        this.name = name;
        this.marks = marks;
    }
}

package com.java.handson.access.specifiers.pkg2;
import com.java.handson.access.specifiers.pkg1.Student;

public class EngineeringStudent extends Student {

    public EngineeringStudent(int rollNumber, String name, int marks) {
        super(rollNumber, name, marks);
    }
    public void displayMarks() {
        System.out.println("Marks: " + marks);  // Allowed (protected, accessible in subclass)
    }
}


package com.java.handson.access.specifiers.pkg2;
import com.java.handson.access.specifiers.pkg1.Student;

public class Main {
    public static void main(String[] args) {
        EngineeringStudent student = new EngineeringStudent(101, "Suraj", 70);
        student.displayMarks();
    }
}
Output: Marks: 70

Public Access Specifier

The least restrictive access specifier. Members declared public are accessible from anywhere in the program.

Common Use Case: Used for methods, constructors, and classes that should be universally accessible.

package com.java.handson.access.specifiers.pkg1;

public class Student {
    private int rollNumber;
    String name;
    protected int marks;
    
    public String mainSubject;

    public Student(int rollNumber, String name, int marks) {
        this.rollNumber = rollNumber;
        this.name = name;
        this.marks = marks;
    }
}

package com.java.handson.access.specifiers.pkg2;
import com.java.handson.access.specifiers.pkg1.Student;

public class Main {
    public static void main(String[] args) {
        Student student = new Student(101, "Suraj", 70);
        student.mainSubject = "Maths"; // Allowed (public variable can be accessed anywhere)
        System.out.println("Main Subject: " + student.mainSubject);
    }
}
Output: Main Subject: Maths

Access Specifiers in Different Contexts

Access specifiers in Java apply to classes, variables, methods, and constructors, but their behavior differs based on context. Below is a breakdown of how they work in different scenarios.

Access Specifiers at the Class Level

Access specifiers can be applied to top-level and inner classes.

A top-level class can only have public or default (package-private) access.

Access SpecifierAllowed in Top-Level Class?Behavior
publicYesAccessible from anywhere.
defaultYesAccessible only within the same package.
privateNoNot allowed for top-level classes.
protectedNoNot allowed for top-level classes.

For inner classes (classes inside another class), all four access specifiers are allowed.

public class Outer {

    private class PrivateInner { }   // Only accessible within Outer

    class DefaultInner { }  // Accessible within the same package

    protected class ProtectedInner { }  // Accessible within package and subclasses

    public class PublicInner { }   // Accessible everywhere
}

Access Specifiers for Variables

Variables (fields) can use all four access specifiers.

Access SpecifierAllowed in same Class ?Allowed in the same package?Allowed in Subclass? (Different Package)Allowed in other Packages?
privateYesNoNoNo
defaultYesYesNoNo
protectedYesYesYesNo
publicYesYesYesYes
class Example {

    private int privateVar = 10;  // Only accessible within this class

    int defaultVar = 20;  // Accessible within the same package

    protected int protectedVar = 30;  // Accessible within the same package & subclasses

    public int publicVar = 40;  // Accessible from anywhere
}

Access Specifiers for Methods

Access specifiers on methods determine their visibility in the class hierarchy.

Access SpecifierAllowed in the same Class?Allowed in the same Package?Allowed in the Subclass? (Different Package)Allowed in the other Packages?
privateYesNoNoNo
defaultYesYesNoNo
protectedYesYesYesNo
publicYesYesYesYes

Write a program to override a protected method

class Parent {
    protected void display() { 
        System.out.println("Parent's Protected Method");
    }
}

class Child extends Parent {
    @Override
    public void display() {  // Allowed (Can increase visibility to public)
        System.out.println("Child's Public Method");
    }
}

Access Specifiers for Constructors

Access specifiers can be used on constructors to control object creation.

class Example {

    private Example() { }  // Cannot create an object from outside this class

    Example(int x) { }     // Accessible within the same package

    protected Example(String str) { }  // Accessible within package and subclasses

    public Example(double y) { }  // Accessible from anywhere
}

Write a program using a private constructor ( Singleton design pattern )

class Singleton {
    private static Singleton instance;

    private Singleton() { }  // Private constructor

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton();
        }
        return instance;
    }
}

Access Specifiers in Interfaces

1. Methods in interfaces are always public (before Java 9).

2. Fields in interfaces are public static final by default.

interface MyInterface {
    int VALUE = 10;  // public static final by default
    void display();  // public abstract by default
}

Best Practices for Using Access Specifiers

Access specifiers play a crucial role in ensuring the encapsulation, security, and maintainability of your Java applications. Below are some best practices to follow when using them.

Use private for Data Hiding (Encapsulation)

1. Always declare instance variables as private to prevent direct access and modification.

2. Use public getters and setters to control access to private fields.

public class Student {
    private int rollNumber;  // Private field

    public int getRollNumber() {  // Public getter
        return rollNumber;
    }

    public void setRollNumber(int rollNumber) {  // Public setter
        if (rollNumber > 0) {
            this.rollNumber = rollNumber;
        }
    }
}

Avoid Using Public Fields

1. Public fields can be modified from anywhere, breaking encapsulation.

2. Instead, use private fields with public methods.

Bad Practice (Avoid This):

public class Car {
    public int speed;  // Anyone can change this directly
}

Good Practice:

public class Car {
    private int speed;  // Data hiding

    public int getSpeed() {
        return speed;
    }

    public void setSpeed(int speed) {
        if (speed >= 0) {  // Adding validation
            this.speed = speed;
        }
    }
}

Minimize Public Methods

1. Keep methods private unless they need to be accessed outside the class.

2. Mark methods protected or default if they should be used only within a package or subclass.

3. If a method is only used inside the class, make it private.

Use Protected for Inheritance (But Cautiously)

1. The protected members should only be used for methods or fields that must be accessed by subclasses.

2. Do not use protected if the field/method is not meant to be overridden.

Use Default (Package-Private) Access for Internal Use

1. If a class, method, or variable is only needed within the same package, do not make it public.

2. Use default access (no modifier) to restrict visibility within the package.

Do Not Overexpose Classes (public vs default)

1. Avoid making every class public unless necessary.

2. If a class is only needed within a package, keep it default (package-private).

Restrict protected and public Methods in Abstract Classes

1. If a method should only be implemented by subclasses, mark it protected instead of public.

2. If a method should not be accessible outside, keep it private.

Conclusion

Access specifiers in Java play a crucial role in controlling access to classes, methods, and variables, ensuring encapsulation, security, and maintainability. By using them effectively, developers can protect data, restrict unintended access, and enforce proper design principles in their applications.

Key takeaways

private – Best for encapsulation; restricts access within the class.
default (package-private) – Limits access within the same package; useful for internal implementation.
protected – Allows access in subclasses and within the same package; useful in inheritance.
public – Provides unrestricted access across the application; should be used judiciously.

Following best practices—such as keeping fields private, exposing only necessary methods, and restricting access when possible—leads to more secure, modular, and maintainable Java applications. Mastering access specifiers is a fundamental step toward writing clean and efficient Java code.

So this is all about access specifiers in Java. If you have any questions on this topic, please raise them in the comments section. If you liked this article, then please share this post with your friends and colleagues.

Leave a Comment