What is the difference between public, protected, package-private and private in Java?
Categories:
Understanding Java Access Modifiers: public, protected, package-private, and private

Explore the four Java access modifiers – public, protected, package-private (default), and private – to control visibility and encapsulation within your applications. Learn how each modifier impacts class, method, and field accessibility.
In Java, access modifiers are keywords that set the accessibility (visibility) of classes, constructors, methods, and fields. They are a fundamental part of encapsulation, a core principle of Object-Oriented Programming (OOP), which helps in controlling the direct access to data and methods, thereby protecting the integrity of the object. Understanding these modifiers is crucial for writing robust, maintainable, and secure Java code.
The Four Pillars of Access Control
Java provides four primary access modifiers, each with a distinct scope of visibility. These modifiers dictate from where a member (or class) can be accessed. Let's delve into each one, starting from the most restrictive to the least restrictive.
classDiagram class PublicClass { + publicMethod() + publicField } class ProtectedClass { # protectedMethod() # protectedField } class PackagePrivateClass { ~ packagePrivateMethod() ~ packagePrivateField } class PrivateClass { - privateMethod() - privateField } PublicClass --> ProtectedClass : extends ProtectedClass --> PackagePrivateClass : extends PackagePrivateClass --> PrivateClass : extends note for PublicClass "Accessible everywhere" note for ProtectedClass "Accessible within package and by subclasses" note for PackagePrivateClass "Accessible only within the same package" note for PrivateClass "Accessible only within the declaring class"
Class diagram illustrating the hierarchy and scope of Java access modifiers.
1. private: The Most Restrictive
The private
access modifier is the most restrictive. Members (fields or methods) declared as private
are only accessible from within the class in which they are declared. They are not visible to any other class, even subclasses within the same package. This modifier is primarily used for implementing encapsulation, hiding the internal implementation details of a class from the outside world.
package com.example.app;
class MyClass {
private String secretData = "Top Secret";
private void revealSecret() {
System.out.println(secretData);
}
public void accessSecret() {
revealSecret(); // Accessible within the same class
}
}
class AnotherClass {
public void tryAccess() {
MyClass obj = new MyClass();
// obj.secretData; // Compile-time error: secretData has private access
// obj.revealSecret(); // Compile-time error: revealSecret() has private access
}
}
Example of private access modifier in Java.
2. package-private (Default): Within the Package
If you don't explicitly specify an access modifier, the member or class is considered package-private
(also known as 'default' access). This means it is accessible only within its own package. It's more restrictive than protected
and public
, but less restrictive than private
. This is often used for utility classes or helper methods that are only relevant to other classes within the same package.
package com.example.app;
class PackageClass {
String packageName = "com.example.app"; // package-private field
void displayPackageName() { // package-private method
System.out.println("Current Package: " + packageName);
}
}
class PackageUser {
public void usePackageClass() {
PackageClass pc = new PackageClass();
System.out.println(pc.packageName); // Accessible within the same package
pc.displayPackageName(); // Accessible within the same package
}
}
// In a different package (e.g., com.example.other):
// import com.example.app.PackageClass; // Cannot import package-private class
// class OtherPackageUser {
// public void tryAccess() {
// PackageClass pc = new PackageClass(); // Compile-time error
// }
// }
Example of package-private (default) access modifier.
3. protected: Package and Subclasses
The protected
access modifier allows members to be accessed within the same package and by subclasses, even if those subclasses are in a different package. This is particularly useful when designing inheritance hierarchies where you want to allow subclasses to access certain parent class members, but restrict access from unrelated classes.
package com.example.base;
public class BaseClass {
protected String protectedMessage = "Hello from BaseClass";
protected void showProtectedMessage() {
System.out.println(protectedMessage);
}
}
// In the same package (com.example.base):
class SamePackageClass {
public void accessBase() {
BaseClass bc = new BaseClass();
System.out.println(bc.protectedMessage); // Accessible
bc.showProtectedMessage(); // Accessible
}
}
// In a different package (e.g., com.example.derived):
package com.example.derived;
import com.example.base.BaseClass;
class DerivedClass extends BaseClass {
public void accessProtected() {
System.out.println(protectedMessage); // Accessible by subclass
showProtectedMessage(); // Accessible by subclass
}
}
class UnrelatedClass {
public void tryAccess() {
BaseClass bc = new BaseClass();
// bc.protectedMessage; // Compile-time error: protected access
// bc.showProtectedMessage(); // Compile-time error: protected access
}
}
Example of protected access modifier.
4. public: The Least Restrictive
The public
access modifier is the least restrictive. Members (fields or methods) or classes declared as public
are accessible from anywhere. This means they can be accessed by any other class, regardless of the package. public
is typically used for methods that define the public interface of a class, allowing other parts of the application or external systems to interact with it.
package com.example.api;
public class PublicService {
public String serviceName = "Global Service";
public void executeService() {
System.out.println("Executing: " + serviceName);
}
}
// In any package (e.g., com.example.main):
package com.example.main;
import com.example.api.PublicService;
public class MainApp {
public static void main(String[] args) {
PublicService service = new PublicService();
System.out.println(service.serviceName); // Accessible from anywhere
service.executeService(); // Accessible from anywhere
}
}
Example of public access modifier.
private
and only increase visibility (package-private
, protected
, public
) if absolutely necessary for the class's intended functionality or its interaction with other components. This practice, known as 'least privilege,' enhances encapsulation and reduces potential side effects.Summary of Access Levels
The following table summarizes the accessibility of members based on their access modifier:

Java Access Modifier Visibility Table
Understanding these distinctions is vital for proper object-oriented design in Java. By carefully choosing the right access modifier, you can create well-encapsulated, modular, and maintainable code.