What is a Java ClassLoader?
The Java Classloader, an integral component of the Java Runtime Environment (JRE), operates dynamically by loading Java classes into the Java Virtual Machine (JVM). Unlike programs written in C or C++, a Java program is not comprised of a solitary executable file, but rather consists of numerous individual class files, each representing a distinct Java class. Typically, classes are loaded into memory on an as-needed basis, meaning that these Java class files are not all loaded simultaneously. Instead, they are fetched into memory when required by the program, facilitated by the Class Loader.
The Class Loader serves as a crucial element within the Java Execution Engine, responsible for retrieving binary data from the .class files available in the classpath and loading it into the Method Area. The loading process of a class into the method area transpires solely during the initial encounter of the class within the running Java application. Subsequent references to the class utilize the preexisting data stored in the method area, unless the class has been explicitly unloaded.
ClassLoader in Java works on three principle:
- Delegation
- Visibility
- Uniqueness
The Delegation principle in class loading entails the forwarding of class loading requests to the parent class loader. Only when the parent class loader is unable to locate or load the requested class, does the current class loader proceed with loading the class. This principle establishes a hierarchical structure in which class loading responsibilities are delegated, ensuring a systematic and efficient approach to class loading.
The Visibility principle complements the Delegation principle by granting the child class loader the ability to access all classes loaded by its parent ClassLoader. However, the inverse is not true: the parent class loader does not possess visibility into classes loaded by its child. This principle establishes clear boundaries and encapsulation between class loaders, enabling each class loader to maintain its own set of loaded classes while still allowing access to shared classes in the parent class loader.
The Uniqueness principle is another vital aspect of class loading, ensuring that a class is loaded only once. This principle is primarily accomplished through the implementation of the Delegation principle, which prevents redundant class loading. By delegating the responsibility of class loading to the parent class loader, the child class loader avoids reloading a class that has already been loaded by the parent. This guarantees that each class is loaded exactly once, eliminating unnecessary duplication and maintaining consistency throughout the class loading process.
Every Java Virtual Machine (JVM) is equipped with a built-in class loader known as the primordial class loader. This specific class loader holds a unique status within the virtual machine. It is considered special because the JVM assumes that the primordial class loader has access to a repository of trusted classes that can be executed by the virtual machine without undergoing the usual verification process.
Upon the initiation of a Java Virtual Machine, three distinct class loaders are employed:
- Bootstrap Class Loader: The bootstrap class loader, also referred to as the primordial class loader, is responsible for loading essential classes that form the foundation of the Java platform. These classes are typically included in the JVM implementation itself and are considered fundamental for the operation of the virtual machine. The bootstrap class loader is an integral part of the JVM and operates at the lowest level.
- Extension Class Loader: The extension class loader is responsible for loading classes from the Java extension directories, such as the "lib/ext" directory in the Java installation. This class loader facilitates the utilization of additional libraries and extensions that are not part of the core Java platform. It operates as an intermediate class loader, positioned between the bootstrap class loader and the application class loader.
- Application Class Loader: The application class loader, also known as the system class loader, handles the loading of classes from the application's classpath. It is responsible for locating and loading the application-specific classes and resources. The application class loader forms the topmost layer in the class loading hierarchy and is typically implemented by the JVM to meet the requirements of a specific application or environment.
Building a SimpleClassLoader
A class loader starts by being a subclass of java.lang.ClassLoader . The only abstract method that must be implemented is loadClass(). The flow of loadClass() is as follows:
- Verify class name.
- Check to see if the class requested has already been loaded.
- Check to see if the class is a "system" class.
- Attempt to fetch the class from this class loader's repository.
- Define the class for the Virtual Machine.
- Resolve the class.
- Return the class to the caller.
How the very first class loaded?
Class loaders in Java follow a hierarchical structure. The initial class is loaded through the assistance of the public static main() method declared in your class. Once the initial class is loaded and executed, subsequent classes are loaded by the classes that are already loaded and running within the program.
The process starts with the entry point of the Java program, typically defined by the main() method. The initial class containing the main() method is loaded by the JVM's built-in class loader, such as the application class loader. This class loader is responsible for locating and loading the classes specified in the main() method.
As the program execution progresses, additional classes are required to fulfill the program's functionality. These classes are loaded by the class loaders of the previously loaded classes. Each class loader is responsible for locating and loading the classes it depends on.
Classloader hierarchy
When a new Java Virtual Machine (JVM) is launched, the initial responsibility of loading crucial Java classes, including those from the java.lang package, as well as other runtime classes, falls upon the bootstrap classloader. Positioned as the parent of all other classloaders, the bootstrap classloader assumes a unique role without a parent of its own. Following the bootstrap classloader, the extension classloader takes center stage in the loading process.
As a child of the bootstrap classloader, the extension classloader assumes the task of loading classes from all .jar files residing in the java.ext.dirs path. These classes are made available regardless of the Java Virtual Machine's classpath. This classloader plays a key role in the second phase of class loading.
Lastly, the system classpath classloader takes the spotlight, being of utmost importance to developers. Positioned as the immediate child of the extension classloader, it takes charge of loading classes from directories and jar files that are specified through various means. These specifications can include the CLASSPATH environment variable, the java.class.path system property, or the -classpath command line option.
Most Java programmers will never need to explicitly use class loaders (except to load resources so that it still works when they're bundled in JARs), let alone write their own. ClassLoaders are used in very large systems and server applications to do things like:
- Modularize a system and load, unload and update modules at runtime
- Use different versions of an API library (e.g. an XML parser) in parallel
- Isolate different applications running within the same JVM (ensuring they don't interfere with each other, e.g. through static variables)
Class loaders play a vital role within the Java Virtual Machine (JVM) as functional components responsible for loading class data from .class files or even from remote sources, into the Method Area situated in the Heap. Each class loader operates within its own distinct namespace, ensuring that classes invoked by a specific class loader remain isolated within its namespace. Consequently, classes invoked by different class loaders lack visibility over each other, thereby enhancing security measures.
The parent-child delegation mechanism employed by class loaders further reinforces the security aspect. This mechanism guarantees that unauthorized code cannot compromise Java API classes. By delegating the loading process to parent class loaders, the Java runtime system establishes a robust safeguard against potential hacking attempts. The delegation mechanism ensures that only authorized class loaders are granted access to the Java API classes, thus maintaining the integrity and security of the Java environment.
The presence of class loaders provides an abstraction layer that shields the Java runtime from the complexities of file systems and file operations when executing Java programs. Class loaders abstract away the intricacies of locating and loading class files, freeing the Java runtime from the need to directly interact with the underlying file system.
One noteworthy aspect is that Java ClassLoader itself is implemented in the Java language. This feature bestows the advantage of simplicity and flexibility upon developers, as it enables them to create their own custom class loaders without investigating into the intricate details of the JVM. Developers have the freedom to tailor class loading behavior to suit specific requirements, without requiring an in-depth understanding of the internal workings of the JVM.
- Java Interview Questions-Core Faq - 1
- Java Interview Questions-Core Faq - 2
- Java Interview Questions-Core Faq - 3
- Features of Java Programming Language (2024)
- Difference between Java and JavaScript?
- What is the difference between JDK and JRE?
- What gives Java its 'write once and run anywhere' nature?
- What is JVM and is it platform independent?
- What is Just-In-Time (JIT) compiler?
- What is the garbage collector in Java?
- What is NullPointerException in Java
- Difference between Stack and Heap memory in Java
- How to set the maximum memory usage for JVM?
- What is numeric promotion?
- Generics in Java
- Static keyword in Java
- What are final variables in Java?
- How Do Annotations Work in Java?
- How do I use the ternary operator in Java?
- What is instanceof keyword in Java?
- What are fail-safe and fail-fast Iterators in Java
- What are method references in Java?
- "Cannot Find Symbol" compile error
- Difference between system.gc() and runtime.gc()
- How to convert TimeStamp to Date in Java?
- Does garbage collection guarantee that a program will not run out of memory?
- How setting an Object to null help Garbage Collection?
- How do objects become eligible for garbage collection?
- How to calculate date difference in Java
- Difference between Path and Classpath in Java
- Is Java "pass-by-reference" or "pass-by-value"?
- Difference between static and nonstatic methods java
- Why Java does not support pointers?
- What is a package in Java?
- What are wrapper classes in Java?
- What is singleton class in Java?
- Difference between Java Local Variable, Instance Variable and a Class Variable?
- Can a top level class be private or protected in Java
- Are Polymorphism , Overloading and Overriding similar concepts?
- Locking Mechanism in Java
- Why Multiple Inheritance is Not Supported in Java
- Why Java is not a pure Object Oriented language?
- Static class in Java
- Difference between Abstract class and Interface in Java
- Why do I need to override the equals and hashCode methods in Java?
- Why does Java not support operator overloading?
- Anonymous Classes in Java
- Static Vs Dynamic class loading in Java
- Why am I getting a NoClassDefFoundError in Java?
- How to Generate Random Number in Java
- What's the meaning of System.out.println in Java?
- What is the purpose of Runtime and System class in Java?
- The finally Block in Java
- Difference between final, finally and finalize
- What is try-with-resources in java?
- What is a stacktrace?
- Why String is immutable in Java ?
- What are different ways to create a string object in Java?
- Difference between String and StringBuffer/StringBuilder in Java
- Difference between creating String as new() and literal | Java
- How do I convert String to Date object in Java?
- How do I create a Java string from the contents of a file?
- What actually causes a StackOverflow error in Java?
- Why is char[] preferred over String for storage of password in Java
- What is I/O Filter and how do I use it in Java?
- Serialization and Deserialization in Java
- Understanding transient variables in Java
- What is Externalizable in Java?
- What is the purpose of serialization/deserialization in Java?
- What is the Difference between byte stream and Character streams
- How to append text to an existing file in Java
- How to convert InputStream object to a String in Java
- What is the difference between Reader and InputStream in Java
- Introduction to Java threads
- Synchronization in Java
- Static synchronization Vs non static synchronization in Java
- Deadlock in Java with Examples
- What is Daemon thread in Java
- Implement Runnable vs Extend Thread in Java
- What is the volatile keyword in Java
- What are the basic interfaces of Java Collections Framework
- Difference between ArrayList and Vector | Java
- What is the difference between ArrayList and LinkedList?
- What is the difference between List and Set in Java
- Difference between HashSet and HashMap in Java
- Difference between HashMap and Hashtable in Java?
- How does the hashCode() method of java works?
- Difference between capacity() and size() of Vector in Java
- What is a Java ClassNotFoundException?
- How to fix java.lang.UnsupportedClassVersionError