Java Modifiers
Keywords that control access and behavior
🔐 What are Modifiers?
Modifiers are keywords that control access levels and behavior of classes, methods, and attributes. They determine who can access your code and how it behaves, providing security and structure to your programs.
public class MyClass {
private String secret; // Only this class can access
public String name; // Anyone can access
static int count; // Belongs to class, not object
}
Types of Modifiers
public
Accessible from anywhere
public String name;
private
Only accessible within same class
private int age;
protected
Accessible within package and subclasses
protected double salary;
static
Belongs to class, not object instance
static int count;
🔹 Access Modifiers
Access modifiers control who can access your classes, methods, and attributes:
// Student.java
public class Student {
// Public - accessible from anywhere
public String name;
public int studentId;
// Private - only accessible within this class
private double gpa;
private String socialSecurityNumber;
// Protected - accessible within package and subclasses
protected String email;
protected String phoneNumber;
// Package-private (no modifier) - accessible within same package
String address;
String emergencyContact;
// Constructor
public Student(String name, int id, double gpa) {
this.name = name;
this.studentId = id;
this.gpa = gpa; // Can access private attribute within same class
}
// Public method - anyone can call
public void displayPublicInfo() {
System.out.println("Name: " + name);
System.out.println("ID: " + studentId);
}
// Private method - only this class can call
private boolean validateGPA(double gpa) {
return gpa >= 0.0 && gpa <= 4.0;
}
// Public method to access private data (getter)
public double getGPA() {
return gpa;
}
// Public method to modify private data (setter)
public void setGPA(double newGpa) {
if (validateGPA(newGpa)) { // Can call private method within same class
this.gpa = newGpa;
System.out.println("GPA updated to: " + gpa);
} else {
System.out.println("Invalid GPA value");
}
}
// Protected method
protected void displayContactInfo() {
System.out.println("Email: " + email);
System.out.println("Phone: " + phoneNumber);
}
}
// StudentExample.java
public class StudentExample {
public static void main(String[] args) {
Student student = new Student("Alice Johnson", 12345, 3.8);
// Accessing public attributes and methods
System.out.println("Student Name: " + student.name); // OK - public
System.out.println("Student ID: " + student.studentId); // OK - public
student.displayPublicInfo(); // OK - public method
// Accessing private attributes - THESE WOULD CAUSE ERRORS!
// System.out.println(student.gpa); // ERROR - private
// student.validateGPA(3.5); // ERROR - private method
// Using public methods to access private data
System.out.println("GPA: " + student.getGPA()); // OK - public getter
student.setGPA(3.9); // OK - public setter
// Accessing package-private attributes
student.address = "123 Main St"; // OK - same package
student.emergencyContact = "John Doe"; // OK - same package
System.out.println("Address: " + student.address);
}
}
Output:
Student Name: Alice Johnson Student ID: 12345 Name: Alice Johnson ID: 12345 GPA: 3.8 GPA updated to: 3.9 Address: 123 Main St
🔹 Static Modifier
The static modifier makes attributes and methods belong to the class rather than individual objects:
// Counter.java
public class Counter {
// Static attribute - shared by all objects
private static int totalCount = 0;
// Instance attribute - unique to each object
private int instanceCount = 0;
private String name;
// Constructor
public Counter(String name) {
this.name = name;
totalCount++; // Increment static counter
System.out.println("Counter '" + name + "' created. Total counters: " + totalCount);
}
// Instance method - works with specific object
public void increment() {
instanceCount++;
System.out.println(name + " count: " + instanceCount);
}
// Static method - belongs to class, not object
public static int getTotalCount() {
return totalCount;
}
// Static method to reset all counters
public static void resetTotalCount() {
totalCount = 0;
System.out.println("Total count reset to 0");
}
// Instance method to get instance count
public int getInstanceCount() {
return instanceCount;
}
// Instance method to display info
public void displayInfo() {
System.out.println("=== Counter Info ===");
System.out.println("Name: " + name);
System.out.println("Instance Count: " + instanceCount);
System.out.println("Total Counters: " + totalCount);
System.out.println();
}
}
// CounterExample.java
public class CounterExample {
public static void main(String[] args) {
// Check initial total count (using static method)
System.out.println("Initial total count: " + Counter.getTotalCount());
// Create counter objects
Counter counter1 = new Counter("Counter A");
Counter counter2 = new Counter("Counter B");
Counter counter3 = new Counter("Counter C");
// Use instance methods
counter1.increment();
counter1.increment();
counter1.displayInfo();
counter2.increment();
counter2.increment();
counter2.increment();
counter2.displayInfo();
counter3.increment();
counter3.displayInfo();
// Check total count using static method
System.out.println("Final total count: " + Counter.getTotalCount());
// Reset total count using static method
Counter.resetTotalCount();
System.out.println("After reset: " + Counter.getTotalCount());
}
}
Output:
Initial total count: 0 Counter 'Counter A' created. Total counters: 1 Counter 'Counter B' created. Total counters: 2 Counter 'Counter C' created. Total counters: 3 Counter A count: 1 Counter A count: 2 === Counter Info === Name: Counter A Instance Count: 2 Total Counters: 3 Counter B count: 1 Counter B count: 2 Counter B count: 3 === Counter Info === Name: Counter B Instance Count: 3 Total Counters: 3 Counter C count: 1 === Counter Info === Name: Counter C Instance Count: 1 Total Counters: 3 Final total count: 3 Total count reset to 0 After reset: 0
🔹 Final Modifier
The final modifier makes variables constant and prevents method overriding:
// MathConstants.java
public class MathConstants {
// Final attributes - constants that cannot be changed
public static final double PI = 3.14159;
public static final int MAX_STUDENTS = 30;
public static final String SCHOOL_NAME = "Java Academy";
// Final instance variable - must be initialized in constructor
private final String studentId;
private final int enrollmentYear;
// Regular variables that can be changed
private String name;
private double gpa;
// Constructor
public MathConstants(String studentId, int enrollmentYear, String name) {
this.studentId = studentId; // Final variable can be set once
this.enrollmentYear = enrollmentYear; // Final variable can be set once
this.name = name;
}
// Final method - cannot be overridden in subclasses
public final void displayStudentId() {
System.out.println("Student ID: " + studentId);
System.out.println("Enrollment Year: " + enrollmentYear);
}
// Regular method that can be overridden
public void displayInfo() {
System.out.println("Name: " + name);
System.out.println("GPA: " + gpa);
displayStudentId(); // Call final method
}
// Static method using final constants
public static double calculateCircleArea(double radius) {
return PI * radius * radius; // Using final constant
}
// Method to demonstrate final variables
public void demonstrateFinal() {
final int localConstant = 100; // Final local variable
System.out.println("Constants:");
System.out.println("PI: " + PI);
System.out.println("Max Students: " + MAX_STUDENTS);
System.out.println("School: " + SCHOOL_NAME);
System.out.println("Local Constant: " + localConstant);
// These would cause compilation errors:
// PI = 3.14; // ERROR - cannot modify final variable
// studentId = "NEW123"; // ERROR - cannot modify final variable
// localConstant = 200; // ERROR - cannot modify final variable
}
// Getters and setters
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public double getGpa() { return gpa; }
public void setGpa(double gpa) { this.gpa = gpa; }
// Getters for final variables (no setters - they can't be changed)
public String getStudentId() { return studentId; }
public int getEnrollmentYear() { return enrollmentYear; }
}
// FinalExample.java
public class FinalExample {
public static void main(String[] args) {
// Create student with final values
MathConstants student = new MathConstants("STU001", 2023, "John Doe");
// Use final constants
System.out.println("School: " + MathConstants.SCHOOL_NAME);
System.out.println("Max Students: " + MathConstants.MAX_STUDENTS);
// Calculate area using final constant
double area = MathConstants.calculateCircleArea(5.0);
System.out.println("Circle area (radius 5): " + area);
// Display student info
student.setGpa(3.7);
student.displayInfo();
System.out.println();
// Demonstrate final variables
student.demonstrateFinal();
// Can change non-final attributes
student.setName("Jane Doe");
student.setGpa(3.9);
System.out.println("\nAfter changes:");
student.displayInfo();
// Cannot change final attributes
System.out.println("Student ID remains: " + student.getStudentId());
System.out.println("Enrollment year remains: " + student.getEnrollmentYear());
}
}
Output:
School: Java Academy Max Students: 30 Circle area (radius 5): 78.53975 Name: John Doe GPA: 3.7 Student ID: STU001 Enrollment Year: 2023 Constants: PI: 3.14159 Max Students: 30 School: Java Academy Local Constant: 100 After changes: Name: Jane Doe GPA: 3.9 Student ID: STU001 Enrollment Year: 2023 Student ID remains: STU001 Enrollment year remains: 2023
🔹 Modifier Summary
Access Modifiers:
- public: Accessible everywhere
- private: Only within same class
- protected: Within package and subclasses
- package-private (no modifier): Within same package
Non-Access Modifiers:
- static: Belongs to class, not object
- final: Cannot be changed/overridden
- abstract: Must be implemented in subclass
- synchronized: Thread-safe method
Best Practices:
- Use private for internal data
- Use public for methods that others need
- Use static for utility methods and constants
- Use final for constants and unchangeable data