What is the difference between public, protected, package-private and private in Java?
In Java, access modifiers control the visibility and accessibility of classes, methods, and variables. Understanding these modifiers is crucial for writing clean, maintainable, and secure code. By applying the correct access levels, you ensure that your classes and APIs expose only what’s necessary, promoting encapsulation and reducing the risk of accidental misuse.
In this guide, we’ll examine the four primary access levels: public, protected, package-private (default), and private. We’ll clarify their differences and show you when and why to use each one. Whether you’re preparing for interviews or aiming to write more robust code, mastering these modifiers is an essential skill.
Table of Contents
- Overview of Access Modifiers
- public
- protected
- package-private (default)
- private
- When to Use Each Modifier
- Recommended Courses to Deepen Your Understanding
- Additional Resources for Interview Preparation
- Conclusion
1. Overview of Access Modifiers
Access modifiers in Java dictate who can see and interact with certain classes, methods, or fields. The language offers four main levels of access:
- public: Accessible from anywhere in the program.
- protected: Accessible within the same package and by subclasses (even in different packages).
- package-private (default): Accessible only within the same package.
- private: Accessible only within the same class.
In essence, these modifiers form a visibility spectrum from most accessible (public) to least accessible (private).
2. public
Definition:
- The
public
keyword makes a class, method, or variable accessible from anywhere in the program. Any code can reference or invoke apublic
member, regardless of package boundaries.
Common Use Cases:
- Public APIs: Classes and methods intended for client code consumption are often
public
. - Utility Methods: Widely used utility functions may be marked as
public
so all parts of the codebase can use them.
Example:
public class Example { public void doSomething() { System.out.println("This is accessible from anywhere!"); } }
Considerations:
Be cautious with public
since it offers the broadest exposure. Overusing it can lead to bloated APIs and tightly coupled code.
3. protected
Definition:
- The
protected
keyword allows access within the same package and from subclasses, even if those subclasses are located in a different package.
Common Use Cases:
- Inheritance Scenarios: When designing a class for extension, you might mark certain methods or variables as
protected
so that subclasses can leverage or override them. - Framework or Library Design: Protected members let you provide extension points for developers without exposing internals to everyone.
Example:
package com.example; public class Parent { protected void doWork() { System.out.println("Accessible in subclasses and same package"); } } package com.other; import com.example.Parent; public class Child extends Parent { public void run() { doWork(); // Allowed because Child is a subclass of Parent } }
Considerations:
protected
strikes a balance between openness and safety. It’s less accessible than public
but still offers more visibility than strictly necessary for internal functionalities.
4. package-private (default)
Definition:
- Also known as default access or “package-private,” this level applies when no explicit modifier (public, protected, or private) is stated. Items are accessible only within the same package.
Common Use Cases:
- Modular Code Organization: Group related classes in the same package and rely on package-private members for inter-class communication without exposing them publicly.
- Library Internals: A library can expose public APIs and keep internal logic package-private to maintain a clean separation between what’s offered to clients and what’s internal.
Example:
package com.example; class InternalHelper { void assist() { System.out.println("Accessible only within com.example package"); } }
Considerations:
Package-private is a good way to keep your code clean. If certain classes or methods don’t need to be public, making them package-private reduces the risk of unintended external usage.
5. private
Definition:
- The
private
keyword restricts visibility solely to the class in which it’s declared. No external class, subclass, or even other classes in the same package can access private members directly.
Common Use Cases:
- Encapsulation: Hide implementation details and sensitive data. Through getters and setters or controlled methods, you can expose only what’s necessary.
- Data Security: Private fields protect internal state from unintended modifications.
Example:
public class SecureData { private String password; public SecureData(String pwd) { this.password = pwd; } // No direct external access to 'password' unless you provide methods }
Considerations:
private
is the strictest and safest access level. It ensures a clear contract about what parts of a class are internal and shouldn’t be touched by outside code.
6. When to Use Each Modifier
public:
Use for top-level APIs or classes/methods designed for widespread use.
protected:
Use for elements intended for subclasses, allowing extensions without making everything public.
package-private (default):
Use for internal classes and methods that must be shared within a package but not beyond it.
private:
Use for details that are strictly internal to a class. This ensures a strong boundary between a class’s public interface and its internal implementation details.
Balancing these modifiers helps maintain cleaner, safer, and more robust codebases.
7. Recommended Courses to Deepen Your Understanding
To write professional-grade Java code, you must know more than just access modifiers. Apply these principles in conjunction with design patterns, system design fundamentals, and coding best practices.
Recommended Courses from DesignGurus.io:
-
Grokking SOLID Design Principles
Learn fundamental principles to structure your codebase and make better decisions about access control, ensuring a clean architecture. -
Grokking Design Patterns for Engineers and Managers
Understanding design patterns allows you to combine these access levels with proven solutions, creating flexible and maintainable systems.
For system design and coding interview mastery:
8. Additional Resources for Interview Preparation
Blogs by DesignGurus.io:
YouTube Channel:
Explore the DesignGurus YouTube Channel for guides on system design, coding patterns, and more.
Mock Interviews and Services:
Gain personalized feedback from ex-FAANG engineers and elevate your interview game.
9. Conclusion
Java’s access modifiers—public, protected, package-private, and private—are essential tools for controlling how classes and their members interact. By applying them thoughtfully, you’ll write more maintainable, modular, and secure code. Pairing this knowledge with a strong grasp of design principles and patterns prepares you for tackling complex challenges, excelling in interviews, and designing systems that scale gracefully.
Use access modifiers wisely, protect your code’s integrity, and elevate your software engineering craft.