Access Modifiers in Java: The Complete Guide

Introduction

Imagine you're in a house with different rooms. Some rooms are open to everyone (public), some are only for family members (protected), some are just for you (private), and some follow the neighborhood rules (package-private). Access modifiers in Java work exactly like this - they control who can access your classes, methods, and variables!

Access modifiers are keywords that set the accessibility (visibility) of classes, methods, constructors, and fields. They're fundamental to encapsulation - one of the core principles of object-oriented programming.


What are Access Modifiers?

Access modifiers determine the scope and visibility of Java elements. They help you implement encapsulation by hiding internal implementation details and exposing only what's necessary.

The Four Access Levels:

ModifierClassPackageSubclassWorld
privateβœ…βŒβŒβŒ
default (no modifier)βœ…βœ…βŒβŒ
protectedβœ…βœ…βœ…βŒ
publicβœ…βœ…βœ…βœ…

Code Explanation with Examples

Example 1: Comprehensive Access Modifier Demonstration

// File: Animal.java
public class Animal {
// 🎯 PUBLIC: Accessible from anywhere
public String publicName;
public void publicMethod() {
System.out.println("Public method - anyone can call me!");
}
// 🎯 PROTECTED: Accessible in package + subclasses (even in different packages)
protected String protectedSpecies;
protected void protectedMethod() {
System.out.println("Protected method - package and subclasses only");
}
// 🎯 DEFAULT (PACKAGE-PRIVATE): No modifier - accessible only in same package
String defaultHabitat; // No modifier = default access
void defaultMethod() {
System.out.println("Default method - same package only");
}
// 🎯 PRIVATE: Accessible only within the same class
private String privateSecret;
private void privateMethod() {
System.out.println("Private method - only I can call myself!");
}
// Constructor
public Animal(String name, String species, String habitat) {
this.publicName = name;
this.protectedSpecies = species;
this.defaultHabitat = habitat;
this.privateSecret = "Classified information";
}
// 🎯 Public method that uses private members (ENCAPSULATION)
public String getPublicInfo() {
return publicName + " is a " + protectedSpecies + " living in " + defaultHabitat;
}
// 🎯 Protected method that can access private members
protected String getProtectedInfo() {
return "Species: " + protectedSpecies + ", Secret: " + privateSecret;
}
// 🎯 Public method exposing controlled access to private data
public void revealSecret() {
privateMethod(); // Can call private method from within class
System.out.println("Revealing secret: " + privateSecret);
}
// 🎯 Demonstration of access within same class
public void demonstrateInternalAccess() {
System.out.println("\n=== INTERNAL ACCESS DEMONSTRATION ===");
System.out.println("Accessing all fields from within the same class:");
System.out.println("Public: " + publicName);
System.out.println("Protected: " + protectedSpecies);
System.out.println("Default: " + defaultHabitat);
System.out.println("Private: " + privateSecret);
// Calling all methods from within same class
publicMethod();
protectedMethod();
defaultMethod();
privateMethod();
}
}
// File: Dog.java (Same package as Animal)
class Dog extends Animal {
private String breed;
public Dog(String name, String breed) {
super(name, "Canine", "Domestic");
this.breed = breed;
}
// 🎯 Can access protected members from parent class
public void displayProtectedInfo() {
System.out.println("Accessing protected member from subclass: " + protectedSpecies);
protectedMethod(); // Can call protected method
}
// 🎯 Can access default members (same package)
public void displayDefaultInfo() {
System.out.println("Accessing default member in same package: " + defaultHabitat);
defaultMethod(); // Can call default method
}
// 🎯 CANNOT access private members from parent class
public void tryAccessPrivate() {
// ❌ This would cause compilation error:
// System.out.println(privateSecret); 
// privateMethod();
System.out.println("Cannot access private members from subclass");
}
public void demonstrateSubclassAccess() {
System.out.println("\n=== SUBCLASS ACCESS DEMONSTRATION ===");
System.out.println("Public access: " + publicName);
System.out.println("Protected access: " + protectedSpecies);
System.out.println("Default access: " + defaultHabitat);
// Private access: NOT POSSIBLE
}
}
// File: AnimalDemo.java (Same package - demonstrating package access)
public class AnimalDemo {
public static void main(String[] args) {
System.out.println("=== ACCESS MODIFIERS DEMONSTRATION ===");
Animal lion = new Animal("Leo", "Lion", "Savannah");
// 🎯 PUBLIC ACCESS - Available everywhere
System.out.println("1. PUBLIC ACCESS:");
System.out.println("Name: " + lion.publicName);
lion.publicMethod();
// 🎯 PROTECTED ACCESS - Available in same package
System.out.println("\n2. PROTECTED ACCESS (same package):");
System.out.println("Species: " + lion.protectedSpecies);
lion.protectedMethod();
// 🎯 DEFAULT ACCESS - Available in same package
System.out.println("\n3. DEFAULT ACCESS (same package):");
System.out.println("Habitat: " + lion.defaultHabitat);
lion.defaultMethod();
// 🎯 PRIVATE ACCESS - NOT available outside class
System.out.println("\n4. PRIVATE ACCESS (outside class):");
// ❌ These would cause compilation errors:
// System.out.println(lion.privateSecret);
// lion.privateMethod();
System.out.println("Private members are not accessible outside the class");
// Using public methods to access private data (ENCAPSULATION)
lion.revealSecret();
// 🎯 Demonstration with subclass
System.out.println("\n" + "=".repeat(50));
Dog buddy = new Dog("Buddy", "Golden Retriever");
buddy.demonstrateSubclassAccess();
buddy.displayProtectedInfo();
buddy.displayDefaultInfo();
// 🎯 Internal access demonstration
System.out.println("\n" + "=".repeat(50));
lion.demonstrateInternalAccess();
}
}

Output:

=== ACCESS MODIFIERS DEMONSTRATION ===
1. PUBLIC ACCESS:
Name: Leo
Public method - anyone can call me!
2. PROTECTED ACCESS (same package):
Species: Lion
Protected method - package and subclasses only
3. DEFAULT ACCESS (same package):
Habitat: Savannah
Default method - same package only
4. PRIVATE ACCESS (outside class):
Private members are not accessible outside the class
Private method - only I can call myself!
Revealing secret: Classified information
==================================================
=== SUBCLASS ACCESS DEMONSTRATION ===
Public access: Buddy
Protected access: Canine
Default access: Domestic
Accessing protected member from subclass: Canine
Protected method - package and subclasses only
Accessing default member in same package: Domestic
Default method - same package only
==================================================
=== INTERNAL ACCESS DEMONSTRATION ===
Accessing all fields from within the same class:
Public: Leo
Protected: Lion
Default: Savannah
Private: Classified information
Public method - anyone can call me!
Protected method - package and subclasses only
Default method - same package only
Private method - only I can call myself!

Example 2: Cross-Package Access Demonstration

// File: com/company/vehicle/Car.java
package com.company.vehicle;
public class Car {
// Different access modifiers
public String publicModel;
protected String protectedEngine;
String defaultColor; // package-private
private String privateVIN;
public Car(String model, String engine, String color, String vin) {
this.publicModel = model;
this.protectedEngine = engine;
this.defaultColor = color;
this.privateVIN = vin;
}
// Public method
public void displayPublicInfo() {
System.out.println("Model: " + publicModel);
}
// Protected method
protected void displayProtectedInfo() {
System.out.println("Engine: " + protectedEngine);
}
// Default method
void displayDefaultInfo() {
System.out.println("Color: " + defaultColor);
}
// Private method
private void displayPrivateInfo() {
System.out.println("VIN: " + privateVIN);
}
// Public method that uses private members
public void getCarDetails() {
System.out.println("Car: " + publicModel + ", " + protectedEngine + ", " + defaultColor);
displayPrivateInfo(); // Internal access to private method
}
}
// File: com/company/vehicle/SportsCar.java (Same package - extends Car)
package com.company.vehicle;
public class SportsCar extends Car {
private int topSpeed;
public SportsCar(String model, String engine, String color, String vin, int topSpeed) {
super(model, engine, color, vin);
this.topSpeed = topSpeed;
}
public void demonstrateAccess() {
System.out.println("=== SUBCLASS IN SAME PACKAGE ===");
// βœ… PUBLIC - Always accessible
System.out.println("Public: " + publicModel);
displayPublicInfo();
// βœ… PROTECTED - Accessible to subclasses
System.out.println("Protected: " + protectedEngine);
displayProtectedInfo();
// βœ… DEFAULT - Accessible in same package
System.out.println("Default: " + defaultColor);
displayDefaultInfo();
// ❌ PRIVATE - Not accessible
// System.out.println(privateVIN);
// displayPrivateInfo();
}
}
// File: com/company/management/Garage.java (Different package)
package com.company.management;
import com.company.vehicle.Car;
public class Garage {
public void maintainCar(Car car) {
System.out.println("=== DIFFERENT PACKAGE ACCESS ===");
// βœ… PUBLIC - Accessible from anywhere
System.out.println("Public: " + car.publicModel);
car.displayPublicInfo();
// ❌ PROTECTED - Not accessible from different package (unless subclass)
// System.out.println(car.protectedEngine);
// car.displayProtectedInfo();
// ❌ DEFAULT - Not accessible from different package
// System.out.println(car.defaultColor);
// car.displayDefaultInfo();
// ❌ PRIVATE - Never accessible outside class
// System.out.println(car.privateVIN);
// car.displayPrivateInfo();
System.out.println("Only public members are accessible from different package");
}
}
// File: com/company/management/FleetManager.java (Different package - extends Car)
package com.company.management;
import com.company.vehicle.Car;
public class FleetManager extends Car {
private int fleetSize;
public FleetManager(String model, String engine, String color, String vin, int fleetSize) {
super(model, engine, color, vin);
this.fleetSize = fleetSize;
}
public void demonstrateCrossPackageAccess() {
System.out.println("=== SUBCLASS IN DIFFERENT PACKAGE ===");
// βœ… PUBLIC - Always accessible
System.out.println("Public: " + publicModel);
displayPublicInfo();
// βœ… PROTECTED - Accessible to subclasses (even in different packages)
System.out.println("Protected: " + protectedEngine);
displayProtectedInfo();
// ❌ DEFAULT - Not accessible from different package
// System.out.println(defaultColor);
// displayDefaultInfo();
// ❌ PRIVATE - Never accessible outside class
// System.out.println(privateVIN);
// displayPrivateInfo();
}
// Special case: accessing through 'this' reference
public void accessThroughThis() {
System.out.println("Access through 'this' reference:");
System.out.println("Public: " + this.publicModel);
System.out.println("Protected: " + this.protectedEngine);
// Default and private still not accessible
}
}
// File: com/company/Main.java (Main class to demonstrate everything)
package com.company;
import com.company.vehicle.Car;
import com.company.vehicle.SportsCar;
import com.company.management.Garage;
import com.company.management.FleetManager;
public class Main {
public static void main(String[] args) {
System.out.println("=== CROSS-PACKAGE ACCESS MODIFIERS DEMO ===");
// Create instances
Car myCar = new Car("Sedan", "V6", "Blue", "12345");
SportsCar sportsCar = new SportsCar("Ferrari", "V8", "Red", "67890", 200);
Garage garage = new Garage();
FleetManager manager = new FleetManager("SUV", "V4", "Black", "11111", 10);
// 🎯 Same package access
System.out.println("\n1. SAME PACKAGE ACCESS:");
sportsCar.demonstrateAccess();
// 🎯 Different package access (non-subclass)
System.out.println("\n2. DIFFERENT PACKAGE ACCESS (Non-subclass):");
garage.maintainCar(myCar);
// 🎯 Different package access (subclass)
System.out.println("\n3. DIFFERENT PACKAGE ACCESS (Subclass):");
manager.demonstrateCrossPackageAccess();
manager.accessThroughThis();
// 🎯 Direct access demonstration
System.out.println("\n4. DIRECT ACCESS FROM MAIN:");
System.out.println("Public: " + myCar.publicModel);
myCar.displayPublicInfo();
// Other access levels not available from main (different package)
}
}

Output:

=== CROSS-PACKAGE ACCESS MODIFIERS DEMO ===
1. SAME PACKAGE ACCESS:
=== SUBCLASS IN SAME PACKAGE ===
Public: Ferrari
Model: Ferrari
Protected: V8
Engine: V8
Default: Red
Color: Red
2. DIFFERENT PACKAGE ACCESS (Non-subclass):
=== DIFFERENT PACKAGE ACCESS ===
Public: Sedan
Model: Sedan
Only public members are accessible from different package
3. DIFFERENT PACKAGE ACCESS (Subclass):
=== SUBCLASS IN DIFFERENT PACKAGE ===
Public: SUV
Model: SUV
Protected: V4
Engine: V4
Access through 'this' reference:
Public: SUV
Protected: V4
4. DIRECT ACCESS FROM MAIN:
Public: Sedan
Model: Sedan

Example 3: Real-World Encapsulation with Access Modifiers

// File: BankAccount.java
public class BankAccount {
// 🎯 PRIVATE: Internal implementation details (ENCAPSULATION)
private String accountNumber;
private double balance;
private String accountHolder;
private String socialSecurityNumber;
private boolean isActive;
// 🎯 PUBLIC: Constructor - needed to create objects
public BankAccount(String accountHolder, String ssn, String accountNumber) {
this.accountHolder = accountHolder;
this.socialSecurityNumber = ssn;
this.accountNumber = accountNumber;
this.balance = 0.0;
this.isActive = true;
}
// 🎯 PUBLIC: Methods that define the interface (what users can do)
public void deposit(double amount) {
if (amount > 0 && isActive) {
balance += amount;
System.out.println("Deposited: $" + amount);
logTransaction("DEPOSIT", amount);
} else {
System.out.println("Invalid deposit amount or inactive account");
}
}
public boolean withdraw(double amount) {
if (amount > 0 && balance >= amount && isActive) {
balance -= amount;
System.out.println("Withdrawn: $" + amount);
logTransaction("WITHDRAW", amount);
return true;
}
System.out.println("Insufficient funds or invalid amount");
return false;
}
public double getBalance() {
return balance;
}
public String getAccountInfo() {
return "Account: " + accountNumber + ", Holder: " + accountHolder + ", Balance: $" + balance;
}
// 🎯 PROTECTED: Methods for internal bank operations
protected void applyInterest(double rate) {
if (isActive && rate > 0) {
double interest = balance * rate / 100;
balance += interest;
System.out.println("Interest applied: $" + interest);
}
}
protected void freezeAccount() {
isActive = false;
System.out.println("Account frozen");
}
protected void unfreezeAccount() {
isActive = true;
System.out.println("Account unfrozen");
}
// 🎯 PRIVATE: Internal helper methods (implementation details)
private void logTransaction(String type, double amount) {
System.out.println("[LOG] " + type + ": $" + amount + " | Balance: $" + balance);
}
private boolean isValidAmount(double amount) {
return amount > 0;
}
// 🎯 DEFAULT: Package-level operations
void internalAudit() {
System.out.println("[AUDIT] Account: " + accountNumber + ", Balance: $" + balance);
}
// 🎯 Demonstration of encapsulation benefits
public void demonstrateEncapsulation() {
System.out.println("\n=== ENCAPSULATION BENEFITS ===");
System.out.println("1. Data Protection: Balance can only be modified through controlled methods");
System.out.println("2. Validation: All operations validate input before modifying state");
System.out.println("3. Flexibility: Internal implementation can change without affecting users");
System.out.println("4. Security: Sensitive data (SSN) is completely hidden");
}
}
// File: SavingsAccount.java (Extends BankAccount)
public class SavingsAccount extends BankAccount {
private double interestRate;
public SavingsAccount(String accountHolder, String ssn, String accountNumber, double interestRate) {
super(accountHolder, ssn, accountNumber);
this.interestRate = interestRate;
}
// 🎯 Can access protected method from parent
public void applyAnnualInterest() {
applyInterest(interestRate); // Protected method accessible to subclass
System.out.println("Annual interest applied at rate: " + interestRate + "%");
}
// 🎯 CANNOT access private members from parent
public void tryAccessPrivate() {
// ❌ These would cause compilation errors:
// System.out.println(balance); // private
// System.out.println(socialSecurityNumber); // private
// logTransaction("TEST", 100); // private
System.out.println("Cannot access private members from subclass");
}
// 🎯 Override with additional functionality
@Override
public boolean withdraw(double amount) {
// Savings account might have withdrawal limits
if (amount > 1000) {
System.out.println("Withdrawal limit exceeded for savings account");
return false;
}
return super.withdraw(amount);
}
}
// File: Bank.java (Same package - demonstrates package access)
public class Bank {
private String bankName;
public Bank(String bankName) {
this.bankName = bankName;
}
// 🎯 Can access default methods in same package
public void performMonthlyAudit(BankAccount account) {
System.out.println("\n=== MONTHLY AUDIT for " + bankName + " ===");
account.internalAudit(); // Default method accessible in same package
}
// 🎯 Can access protected methods in same package
public void handleFraudCase(BankAccount account) {
System.out.println("\n=== FRAUD HANDLING ===");
account.freezeAccount(); // Protected method accessible in same package
}
public void demonstratePackageAccess() {
System.out.println("\n=== PACKAGE-LEVEL ACCESS ===");
BankAccount account = new BankAccount("John Doe", "123-45-6789", "ACC123");
// Can access public, protected, and default members in same package
account.deposit(1000);
account.internalAudit(); // Default access
account.applyInterest(2.5); // Protected access
}
}
// File: BankDemo.java (Main demonstration class)
public class BankDemo {
public static void main(String[] args) {
System.out.println("=== BANK ACCOUNT ENCAPSULATION DEMO ===");
// Create accounts
BankAccount checking = new BankAccount("Alice Smith", "987-65-4321", "CHK001");
SavingsAccount savings = new SavingsAccount("Bob Johnson", "456-78-9012", "SAV001", 2.5);
Bank cityBank = new Bank("City Bank");
// 🎯 Public interface usage
System.out.println("\n1. PUBLIC INTERFACE USAGE:");
checking.deposit(1500);
checking.withdraw(200);
System.out.println("Balance: $" + checking.getBalance());
System.out.println(checking.getAccountInfo());
// 🎯 Savings account with protected access
System.out.println("\n2. SAVINGS ACCOUNT OPERATIONS:");
savings.deposit(5000);
savings.applyAnnualInterest(); // Uses protected method
System.out.println("Savings balance: $" + savings.getBalance());
// 🎯 Package-level access demonstration
System.out.println("\n3. PACKAGE-LEVEL OPERATIONS:");
cityBank.performMonthlyAudit(checking);
cityBank.demonstratePackageAccess();
// 🎯 Encapsulation benefits
System.out.println("\n4. ENCAPSULATION IN ACTION:");
checking.demonstrateEncapsulation();
// 🎯 Attempting invalid operations (prevented by encapsulation)
System.out.println("\n5. INVALID OPERATIONS (PREVENTED):");
// ❌ Direct access to private fields not allowed
// checking.balance = 1000000; // Compilation error
// checking.socialSecurityNumber = "hacked"; // Compilation error
// βœ… Must use public methods with validation
checking.deposit(-100); // Invalid - rejected
checking.withdraw(1000000); // Invalid - rejected
// 🎯 Security demonstration
System.out.println("\n6. SECURITY FEATURES:");
System.out.println("Sensitive data (SSN) is completely hidden from external access");
System.out.println("Balance can only be modified through validated methods");
System.out.println("Internal logging and auditing are hidden implementation details");
}
}

Output:

=== BANK ACCOUNT ENCAPSULATION DEMO ===
1. PUBLIC INTERFACE USAGE:
Deposited: $1500.0
[LOG] DEPOSIT: $1500.0 | Balance: $1500.0
Withdrawn: $200.0
[LOG] WITHDRAW: $200.0 | Balance: $1300.0
Balance: $1300.0
Account: CHK001, Holder: Alice Smith, Balance: $1300.0
2. SAVINGS ACCOUNT OPERATIONS:
Deposited: $5000.0
[LOG] DEPOSIT: $5000.0 | Balance: $5000.0
Interest applied: $125.0
Annual interest applied at rate: 2.5%
Savings balance: $5125.0
3. PACKAGE-LEVEL OPERATIONS:
=== MONTHLY AUDIT for City Bank ===
[AUDIT] Account: CHK001, Balance: $1300.0
=== PACKAGE-LEVEL ACCESS ===
Deposited: $1000.0
[LOG] DEPOSIT: $1000.0 | Balance: $1000.0
[AUDIT] Account: ACC123, Balance: $1000.0
Interest applied: $25.0
4. ENCAPSULATION IN ACTION:
=== ENCAPSULATION BENEFITS ===
1. Data Protection: Balance can only be modified through controlled methods
2. Validation: All operations validate input before modifying state
3. Flexibility: Internal implementation can change without affecting users
4. Security: Sensitive data (SSN) is completely hidden
5. INVALID OPERATIONS (PREVENTED):
Invalid deposit amount or inactive account
Insufficient funds or invalid amount
6. SECURITY FEATURES:
Sensitive data (SSN) is completely hidden from external access
Balance can only be modified through validated methods
Internal logging and auditing are hidden implementation details

Example 4: Access Modifiers with Constructors and Static Members

// File: Student.java
public class Student {
// 🎯 Instance variables with different access levels
public String publicName;
protected int protectedAge;
String defaultGrade; // package-private
private String privateEmail;
// 🎯 Static variables with different access levels
public static String publicSchool = "Public High School";
protected static int protectedStudentCount = 0;
static String defaultPrincipal = "John Smith"; // package-private
private static String privateSchoolMotto = "Knowledge is Power";
// 🎯 CONSTRUCTORS with different access levels
// Public constructor - anyone can create Student objects
public Student(String name, int age, String grade, String email) {
this.publicName = name;
this.protectedAge = age;
this.defaultGrade = grade;
this.privateEmail = email;
protectedStudentCount++;
}
// Protected constructor - only subclasses and same package can use
protected Student(String name, int age) {
this(name, age, "Unknown", "[email protected]");
}
// Default constructor - only same package can use
Student(String name) {
this(name, 0, "Unknown", "[email protected]");
}
// Private constructor - only this class can use (for singleton/factory patterns)
private Student() {
this("Anonymous", 0, "Unknown", "[email protected]");
}
// 🎯 Static factory method using private constructor
public static Student createAnonymousStudent() {
return new Student(); // Can use private constructor within class
}
// 🎯 METHODS with different access levels
// Public method
public void displayPublicInfo() {
System.out.println("Student: " + publicName + ", Grade: " + defaultGrade);
}
// Protected method
protected void displayProtectedInfo() {
System.out.println("Age: " + protectedAge + ", Email: " + privateEmail);
}
// Default method
void displayDefaultInfo() {
System.out.println("All info: " + publicName + ", " + protectedAge + ", " + defaultGrade);
}
// Private method
private void displayPrivateInfo() {
System.out.println("Private email: " + privateEmail);
}
// 🎯 Static methods with different access levels
public static void displayPublicStaticInfo() {
System.out.println("School: " + publicSchool + ", Students: " + protectedStudentCount);
}
protected static void displayProtectedStaticInfo() {
System.out.println("Principal: " + defaultPrincipal + ", Motto: " + privateSchoolMotto);
}
static void displayDefaultStaticInfo() {
System.out.println("School info: " + publicSchool + ", " + defaultPrincipal);
}
private static void displayPrivateStaticInfo() {
System.out.println("Secret motto: " + privateSchoolMotto);
}
// 🎯 Public method that uses private static members
public static void revealMotto() {
displayPrivateStaticInfo();
}
// 🎯 Demonstration method
public void demonstrateAccess() {
System.out.println("\n=== INTERNAL ACCESS DEMONSTRATION ===");
// Instance members
System.out.println("Public: " + publicName);
System.out.println("Protected: " + protectedAge);
System.out.println("Default: " + defaultGrade);
System.out.println("Private: " + privateEmail);
// Static members
System.out.println("Public Static: " + publicSchool);
System.out.println("Protected Static: " + protectedStudentCount);
System.out.println("Default Static: " + defaultPrincipal);
System.out.println("Private Static: " + privateSchoolMotto);
}
}
// File: CollegeStudent.java (Subclass)
public class CollegeStudent extends Student {
private String major;
// Can use public and protected constructors
public CollegeStudent(String name, int age, String grade, String email, String major) {
super(name, age, grade, email); // Public constructor
this.major = major;
}
// Can use protected constructor
public CollegeStudent(String name, int age, String major) {
super(name, age); // Protected constructor
this.major = major;
}
// ❌ Cannot use default or private constructors from different package
// public CollegeStudent(String name) {
//     super(name); // Default constructor - not accessible
// }
public void demonstrateSubclassAccess() {
System.out.println("=== SUBCLASS ACCESS ===");
// Instance members
System.out.println("Public: " + publicName);
System.out.println("Protected: " + protectedAge);
// System.out.println(defaultGrade); // Not accessible (different package)
// System.out.println(privateEmail); // Not accessible
// Static members
System.out.println("Public Static: " + publicSchool);
System.out.println("Protected Static: " + protectedStudentCount);
// System.out.println(defaultPrincipal); // Not accessible
// System.out.println(privateSchoolMotto); // Not accessible
}
// Can access protected methods
public void showProtectedInfo() {
displayProtectedInfo(); // Protected method accessible
}
}
// File: School.java (Same package demonstration)
class School {
public void demonstratePackageAccess() {
System.out.println("=== SAME PACKAGE ACCESS ===");
// Can use public, protected, and default constructors
Student student1 = new Student("John", 16, "10th", "[email protected]"); // Public
Student student2 = new Student("Jane", 15); // Protected
Student student3 = new Student("Mike"); // Default
// Student student4 = new Student(); // Private - not accessible
// Accessing members
System.out.println("Public: " + student1.publicName);
System.out.println("Protected: " + student1.protectedAge);
System.out.println("Default: " + student1.defaultGrade);
// System.out.println(student1.privateEmail); // Not accessible
// Calling methods
student1.displayPublicInfo();
student1.displayProtectedInfo();
student1.displayDefaultInfo();
// student1.displayPrivateInfo(); // Not accessible
// Static access
System.out.println("Public Static: " + Student.publicSchool);
System.out.println("Protected Static: " + Student.protectedStudentCount);
System.out.println("Default Static: " + Student.defaultPrincipal);
// System.out.println(Student.privateSchoolMotto); // Not accessible
}
}
// File: AccessModifiersDemo.java (Main class)
public class AccessModifiersDemo {
public static void main(String[] args) {
System.out.println("=== ACCESS MODIFIERS WITH CONSTRUCTORS AND STATIC ===");
// 🎯 Creating objects with different constructors
Student student1 = new Student("Alice", 17, "11th", "[email protected]");
Student anonymous = Student.createAnonymousStudent();
// 🎯 Access demonstration
student1.demonstrateAccess();
// 🎯 Static access demonstration
System.out.println("\n=== STATIC MEMBER ACCESS ===");
System.out.println("Public static: " + Student.publicSchool);
Student.displayPublicStaticInfo();
// 🎯 Subclass demonstration
System.out.println("\n=== SUBCLASS ACCESS ===");
CollegeStudent collegeStudent = new CollegeStudent("Bob", 20, "A", "[email protected]", "Computer Science");
collegeStudent.demonstrateSubclassAccess();
collegeStudent.showProtectedInfo();
// 🎯 Same package demonstration
System.out.println("\n=== SAME PACKAGE ACCESS ===");
School school = new School();
school.demonstratePackageAccess();
// 🎯 Constructor access summary
System.out.println("\n=== CONSTRUCTOR ACCESS SUMMARY ===");
System.out.println("Public constructor: Accessible from anywhere");
System.out.println("Protected constructor: Accessible in package + subclasses");
System.out.println("Default constructor: Accessible only in same package");
System.out.println("Private constructor: Accessible only within same class");
// 🎯 Static access summary
System.out.println("\n=== STATIC MEMBER ACCESS SUMMARY ===");
System.out.println("Follows the same rules as instance members");
System.out.println("Accessed through ClassName.memberName");
}
}

Output:

=== ACCESS MODIFIERS WITH CONSTRUCTORS AND STATIC ===
=== INTERNAL ACCESS DEMONSTRATION ===
Public: Alice
Protected: 17
Default: 11th
Private: [email protected]
Public Static: Public High School
Protected Static: 2
Default Static: John Smith
Private Static: Knowledge is Power
=== STATIC MEMBER ACCESS ===
Public static: Public High School
School: Public High School, Students: 2
=== SUBCLASS ACCESS ===
=== SUBCLASS ACCESS ===
Public: Bob
Protected: 20
Public Static: Public High School
Protected Static: 3
Age: 20, Email: [email protected]
=== SAME PACKAGE ACCESS ===
=== SAME PACKAGE ACCESS ===
Public: John
Protected: 16
Default: 10th
Student: John, Grade: 10th
Age: 16, Email: [email protected]
All info: John, 16, 10th
Public Static: Public High School
Protected Static: 6
Default Static: John Smith
=== CONSTRUCTOR ACCESS SUMMARY ===
Public constructor: Accessible from anywhere
Protected constructor: Accessible in package + subclasses
Default constructor: Accessible only in same package
Private constructor: Accessible only within same class
=== STATIC MEMBER ACCESS SUMMARY ===
Follows the same rules as instance members
Accessed through ClassName.memberName

Access Modifiers Summary Table

ModifierClassPackageSubclassWorldTypical Use
privateβœ…βŒβŒβŒInternal implementation, sensitive data
defaultβœ…βœ…βŒβŒPackage-level utilities, internal APIs
protectedβœ…βœ…βœ…βŒFramework hooks, subclass customization
publicβœ…βœ…βœ…βœ…Public API, interfaces, constants

Best Practices

  1. Use the most restrictive access level possible - start with private and increase as needed
  2. Make fields private and provide public getters/setters for encapsulation
  3. Use public for API methods that users need to call
  4. Use protected for methods meant to be overridden by subclasses
  5. Use package-private (default) for internal implementation details
  6. Keep constructors private for singleton patterns or factory methods
  7. Use public static final for constants

Common Patterns

Encapsulation Pattern:

public class BankAccount {
private double balance;
public double getBalance() { return balance; }
public void deposit(double amount) { 
if (amount > 0) balance += amount; 
}
}

Singleton Pattern:

public class Singleton {
private static Singleton instance;
private Singleton() {} // Private constructor
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}

Factory Pattern:

public class AnimalFactory {
private AnimalFactory() {} // Private constructor
public static Animal createAnimal(String type) {
switch (type) {
case "dog": return new Dog();
case "cat": return new Cat();
default: throw new IllegalArgumentException();
}
}
}

Conclusion

Access modifiers are fundamental to Java's object-oriented design:

  • βœ… Enable encapsulation by hiding implementation details
  • βœ… Provide security by controlling access to sensitive data
  • βœ… Support maintainability by defining clear APIs
  • βœ… Facilitate code organization through package structuring

Key Takeaways:

  1. private - Class-level privacy (most restrictive)
  2. default - Package-level privacy (no modifier)
  3. protected - Package + subclass access
  4. public - Global access (least restrictive)

Remember: Good access modifier usage is like good architecture - it creates clear boundaries, protects what's important, and makes the system more maintainable and secure. Choose your access levels thoughtfully! πŸ—οΈπŸ”’

Now you have a comprehensive understanding of how to control visibility and build well-encapsulated Java applications!

Leave a Reply

Your email address will not be published. Required fields are marked *


Macro Nepal Helper