Access modifiers in Java are keywords that control the visibility and accessibility of classes, interfaces, variables, methods, and constructors. They are crucial for implementing encapsulation, a core principle of object-oriented programming, which involves bundling data and the methods that operate on that data, and restricting direct access to some of the object’s components. Java provides four access modifiers:
-
public
: The most permissive access level. Members declared aspublic
are accessible from any other class, regardless of whether they are in the same package or a different package. -
protected
: Provides access to members within the same package and also to subclasses (even if they are in a different package). -
default
(no modifier): Also known as package-private. Members with no access modifier are accessible only within the same package. They are not accessible from classes in other packages. -
private
: The most restrictive access level. Members declared asprivate
are only accessible within the same class. They are not accessible from any other class, not even subclasses.
Summary Table:
Access Modifier | Same Class | Same Package | Subclass (Different Package) | Other Package |
---|---|---|---|---|
public |
Yes | Yes | Yes | Yes |
protected |
Yes | Yes | Yes | No |
default (no modifier) |
Yes | Yes | No | No |
private |
Yes | No | No | No |
Detailed Explanation with Examples:
Let’s illustrate the access modifiers with a practical example:
package com.example.access; // Package declaration
class MyClass {
public int publicVar = 10;
protected int protectedVar = 20;
int defaultVar = 30; // No access modifier (default/package-private)
private int privateVar = 40;
public void publicMethod() {
System.out.println("Public method");
System.out.println(privateVar); // Accessing private within the same class is allowed
}
protected void protectedMethod() {
System.out.println("Protected method");
}
void defaultMethod() {
System.out.println("Default method");
}
private void privateMethod() {
System.out.println("Private method");
}
}
class AnotherClass { // In the same package (com.example.access)
public static void main(String[] args) {
MyClass obj = new MyClass();
System.out.println(obj.publicVar); // Accessing public is allowed
System.out.println(obj.protectedVar); // Accessing protected within the same package is allowed
System.out.println(obj.defaultVar); // Accessing default within the same package is allowed
// System.out.println(obj.privateVar); // Compile-time error: private is not accessible
obj.publicMethod();
obj.protectedMethod();
obj.defaultMethod();
// obj.privateMethod(); // Compile-time error: private is not accessible
}
}
package com.example.anotherpackage; // Different package
import com.example.access.MyClass;
class DifferentPackageClass extends MyClass { //Subclass in different package
public static void main(String[] args) {
MyClass obj = new MyClass();
System.out.println(obj.publicVar); // Accessing public is allowed
// System.out.println(obj.protectedVar); // Compile-time error: protected is not accessible from another package without inheritance
// System.out.println(obj.defaultVar); // Compile-time error: default is not accessible from another package
// System.out.println(obj.privateVar); // Compile-time error: private is not accessible
DifferentPackageClass obj2 = new DifferentPackageClass();
System.out.println(obj2.publicVar); // Accessing public is allowed
System.out.println(obj2.protectedVar); // Accessing protected is allowed as it is a subclass
// System.out.println(obj2.defaultVar); // Compile-time error: default is not accessible from another package
// System.out.println(obj2.privateVar); // Compile-time error: private is not accessible
obj.publicMethod();
// obj.protectedMethod(); // Compile-time error: protected is not accessible from another package without inheritance
// obj.defaultMethod(); // Compile-time error: default is not accessible from another package
// obj.privateMethod(); // Compile-time error: private is not accessible
obj2.publicMethod();
obj2.protectedMethod(); // Accessing protected is allowed as it is a subclass
// obj2.defaultMethod(); // Compile-time error: default is not accessible from another package
// obj2.privateMethod(); // Compile-time error: private is not accessible
}
}
Java Public, Protected, Default, Private Keywords
When to Use Which Access Modifier:
-
public
: Use for members that need to be accessible from anywhere. Typically used for the main interface of your classes. -
protected
: Use when you want members to be accessible to subclasses, even if they are in a different package, and also within the same package. Useful for inheritance scenarios. -
default
(no modifier): Use when you want members to be accessible only within the same package. Provides a level of encapsulation within a package. -
private
: Use for members that should only be accessible within the same class. This is the primary way to achieve data hiding and encapsulation.
Best Practices:
-
Minimize access: Start with the most restrictive access level (
private
) and only widen it if necessary. This promotes better encapsulation and reduces the risk of unintended side effects. -
Use
private
for instance variables: Instance variables (data members) should almost always beprivate
. Access to them should be controlled through public “getter” and “setter” methods (also known as accessor and mutator methods). This allows you to validate data and control how it’s modified. -
Consider
protected
for inheritance: If you’re designing classes for inheritance,protected
is often the appropriate access level for members that subclasses need to access but should not be part of the public interface of the class.