Java Access Modifiers are an essential part of Object-Oriented Programming in Java. They control the accessibility, visibility, and usage scope of classes, methods, variables, and constructors. Understanding access modifiers is extremely important for beginners as well as advanced Java programmers because they directly influence encapsulation, data hiding, inheritance rules, package structure, and API design. Access Modifiers in Java determine how different parts of a program will interact with each other, whether components remain exposed or protected, and how objects behave when used across different classes and packages. The most common Java Access Modifiers are public, private, protected, and the default (no modifier). Each modifier has a specific purpose, level of visibility, and typical use cases in real-world Java applications such as enterprise applications, frameworks, APIs, and secure software engineering.
Java provides four types of access modifiers. These modifiers help control where a class member (method, variable, constructor) can be accessed. The four access levels are: public, private, protected, and default (package-private). These access levels help developers apply encapsulation, restrict unauthorized access, improve code maintainability, and follow industry standards for secure programming. Javaβs access modifier design is inspired by the principles of abstraction and modular development, which ensures that different modules of an application can interact safely without exposing unnecessary internal implementation details. Understanding each modifier deeply helps programmers design classes that are flexible, reusable, and secure. The upcoming sections explain each modifier in detail with 10β15+ lines and examples.
The public access modifier is the most permissive access level in Java. When a class, method, or variable is declared public, it can be accessed from anywhere within the program, across packages, subclasses, and external modules. This is useful when creating APIs, libraries, utility classes, or functions that need to be accessed globally. Public modifiers are often used for essential components like main methods, model classes, controllers, or entry-point functionalities in Java applications. It is important, however, to use public access carefully because excessive usage may expose internal implementation details. In well-designed programs, only the necessary methods are declared public while the internal logic is kept hidden. Below is an example demonstrating a public class and public method.
public class PublicDemo {
public int number = 50;
public void display() {
System.out.println("Public Method: Number = " + number);
}
public static void main(String[] args) {
PublicDemo obj = new PublicDemo();
obj.display();
}
}
Public Method: Number = 50
The private access modifier is the most restrictive modifier in Java. When a variable or method is declared private, it becomes accessible only within the same class. Private members cannot be accessed directly from other classes, subclasses, or even classes within the same package. Private modifiers help implement data hiding, which is one of the core principles of object-oriented programming. By making fields private, developers prevent unauthorized modification of data and ensure better control over how values are set or retrieved. Access to private members is usually provided using getter and setter methods. Constructors can also be private, commonly used in Singleton Design Patterns. Below is a clear example showing how private variables work.
class PrivateDemo {
private String message = "Private Data";
private void showMessage() {
System.out.println("Message: " + message);
}
public void accessPrivate() {
showMessage();
}
}
public class TestPrivate {
public static void main(String[] args) {
PrivateDemo obj = new PrivateDemo();
obj.accessPrivate();
}
}
Message: Private Data
When no access modifier is specified, Java uses default access, also called package-private access. This means the class members are accessible only within the same package. Classes with default access cannot be accessed from outside the package. Default access is useful when classes or methods are meant to be shared internally within a module but should not be exposed to the entire application. It promotes modular development and acts as a boundary between packages. Default access is commonly used in frameworks and layered architectures where internal logic must remain hidden. Below is an example demonstrating how default access modifies behavior.
// File: PackageOne/DefaultDemo.java
package PackageOne;
class DefaultDemo {
int value = 100;
void showValue() {
System.out.println("Default Value: " + value);
}
}
// File: PackageOne/TestDefault.java
package PackageOne;
public class TestDefault {
public static void main(String[] args) {
DefaultDemo obj = new DefaultDemo();
obj.showValue();
}
}
Default Value: 100
The protected access modifier allows access within the same package and also to subclasses even if they are in different packages. It is an essential modifier for inheritance-based applications. Protected access is useful when a parent class needs to expose specific functionalities only to its subclasses while keeping them hidden from other classes. Many real-world Java frameworks such as Spring, Hibernate, JDBC, and Swing use protected members to allow customization and extension through inheritance. Protected fields and methods facilitate reusability, controlled extension, and maintainable object-oriented design. The following example demonstrates protected access.
// File: ParentPackage/ParentClass.java
package ParentPackage;
public class ParentClass {
protected String data = "Protected Data";
protected void displayData() {
System.out.println("Inside Parent: " + data);
}
}
// File: ChildPackage/ChildClass.java
package ChildPackage;
import ParentPackage.ParentClass;
public class ChildClass extends ParentClass {
public void accessProtected() {
displayData();
}
public static void main(String[] args) {
ChildClass obj = new ChildClass();
obj.accessProtected();
}
}
Inside Parent: Protected Data
The following comparison helps developers understand how different access modifiers behave across class boundaries. This table is crucial for interview preparation, real-time projects, API development, and object-oriented design. It makes it easy to visualize the levels of access allowed in Java for classes and class members. Understanding this helps in writing secure, modular, object-oriented code.
| Modifier | Same Class | Same Package | Subclass (Different Package) | Different Package |
|---|---|---|---|---|
| public | Yes | Yes | Yes | Yes |
| protected | Yes | Yes | Yes | No |
| default | Yes | Yes | No | No |
| private | Yes | No | No | No |
Access modifiers behave differently depending on whether they are applied to classes or members inside a class. Only public and default access can be used at the top-level class level. Private and protected cannot be applied to top-level classes. Methods and variables, however, support all four access modifiers. Developers use a combination of these modifiers to control how objects interact and how modules communicate. For example, fields are often private, methods commonly public, and constructors may be private or protected based on design patterns. This structured approach helps enforce encapsulation and ensures safe interaction between objects in large-scale applications.
class AccessExample {
public int a = 10;
private int b = 20;
protected int c = 30;
int d = 40; // default
public void showA() {
System.out.println("Public A: " + a);
}
private void showB() {
System.out.println("Private B: " + b);
}
protected void showC() {
System.out.println("Protected C: " + c);
}
void showD() {
System.out.println("Default D: " + d);
}
public static void main(String args[]) {
AccessExample obj = new AccessExample();
obj.showA();
obj.showB();
obj.showC();
obj.showD();
}
}
Public A: 10
Private B: 20
Protected C: 30
Default D: 40
Access modifiers are widely used across professional Java applications such as banking systems, enterprise software, APIs, backend applications, and Android development. Public modifiers are used for API endpoints, controllers, and service classes. Private modifiers are used for sensitive data such as account balance, passwords, configurations, and internal logic that should not be exposed to the outside world. Protected modifiers are widely used in frameworks where base classes provide functionality to child classes, allowing extension but preventing unrestricted access. Default access helps in logical grouping of classes within a package and supports modular application development. Overall, access modifiers are essential tools for maintaining security, performance, readability, modularity, and extensibility.
Java Access Modifiers form the backbone of secure and well-structured object-oriented programming in Java. They help developers control how classes interact, how data flows across modules, and how objects communicate in large-scale applications. Public, private, protected, and default access levels each serve unique purposes that contribute to encapsulation, inheritance, security, and maintainability. Mastering access modifiers is essential for writing professional, secure, and optimized Java programs. This detailed note provides all important concepts, examples, outputs, and explanations necessary for beginners, intermediate learners, and advanced Java developers.
Java is known for its key features such as object-oriented programming, platform independence, robust exception handling, multithreading capabilities, and automatic garbage collection.
The Java Development Kit (JDK) is a software development kit used to develop Java applications. The Java Runtime Environment (JRE) provides libraries and other resources to run Java applications, while the Java Virtual Machine (JVM) executes Java bytecode.
Java is a high-level, object-oriented programming language known for its platform independence. This means that Java programs can run on any device that has a Java Virtual Machine (JVM) installed, making it versatile across different operating systems.
Deadlock is a situation in multithreading where two or more threads are blocked forever, waiting for each other to release resources.
Functional programming in Java involves writing code using functions, immutability, and higher-order functions, often utilizing features introduced in Java 8.
A process is an independent program in execution, while a thread is a lightweight subprocess that shares resources with other threads within the same process.
The Comparable interface defines a natural ordering for objects, while the Comparator interface defines an external ordering.
The List interface allows duplicate elements and maintains the order of insertion, while the Set interface does not allow duplicates and does not guarantee any specific order.
String is immutable, meaning its value cannot be changed after creation. StringBuffer and StringBuilder are mutable, allowing modifications to their contents. The main difference between them is that StringBuffer is synchronized, making it thread-safe, while StringBuilder is not.
Checked exceptions are exceptions that must be either caught or declared in the method signature, while unchecked exceptions do not require explicit handling.
ArrayList is backed by a dynamic array, providing fast random access but slower insertions and deletions. LinkedList is backed by a doubly-linked list, offering faster insertions and deletions but slower random access.
Autoboxing is the automatic conversion between primitive types and their corresponding wrapper classes. For example, converting an int to Integer.
The 'synchronized' keyword in Java is used to control access to a method or block of code by multiple threads, ensuring that only one thread can execute it at a time.
Multithreading in Java allows concurrent execution of two or more threads, enabling efficient CPU utilization and improved application performance.
A HashMap is a collection class that implements the Map interface, storing key-value pairs. It allows null values and keys and provides constant-time performance for basic operations.
Java achieves platform independence by compiling source code into bytecode, which is executed by the JVM. This allows Java programs to run on any platform that has a compatible JVM.
The Serializable interface provides a default mechanism for serialization, while the Externalizable interface allows for custom serialization behavior.
The 'volatile' keyword in Java indicates that a variable's value will be modified by multiple threads, ensuring that the most up-to-date value is always visible.
Serialization is the process of converting an object into a byte stream, enabling it to be saved to a file or transmitted over a network.
The finalize() method is called by the garbage collector before an object is destroyed, allowing for cleanup operations.
The 'final' keyword in Java is used to define constants, prevent method overriding, and prevent inheritance of classes, ensuring that certain elements remain unchanged.
Garbage collection is the process by which the JVM automatically deletes objects that are no longer reachable, freeing up memory resources.
'throw' is used to explicitly throw an exception, while 'throws' is used in method declarations to specify that a method can throw one or more exceptions.
The 'super' keyword in Java refers to the immediate parent class and is used to access parent class methods, constructors, and variables.
The JVM is responsible for loading, verifying, and executing Java bytecode. It provides an abstraction between the compiled Java program and the underlying hardware, enabling platform independence.
Copyrights © 2024 letsupdateskills All rights reserved