JDK, JRE, JVM: Explained in Detailed
Table of contents
- Introduction
- What is a Virtual Machine?
- What is the Java Virtual Machine?
- JDK, JRE, and JVM Relationship
- How Is Java Platform-Independent?
- How Java Works Internally
- JDK (Java Development Kit)
- JRE (Java Runtime Environment)
- JVM (Java Virtual Machine)
- Native Method Libraries of JVM
- JVM Heap Memory (HotSpot Heap Structure)
- Minor, Major, and Full Garbage Collection in JVM
- JDK vs. JRE vs. JVM
- Conclusion
This article explores the key parts of Java: the Java Virtual Machine (JVM), Java Runtime Environment (JRE), and Java Development Kit (JDK).
Introduction
Even if you haven't developed programs in Java, you might have encountered the term Java Virtual Machine (JVM). The JVM is the foundation of the Java ecosystem, allowing Java programs to follow the "write once, run anywhere" principle. This means you can write Java code on one machine and execute it on any other machine with a JVM.
Initially, the JVM was designed exclusively for Java. However, over time, other languages like Scala, Kotlin, and Groovy have been adapted to run on the Java platform. These languages are collectively known as JVM languages. In this article, we will explore the JVM, its workings, and its various components.
What is a Virtual Machine?
Before we dive into the JVM, let's review what a Virtual Machine (VM) is. A virtual machine is software that acts like a physical computer. The virtual machine is called the guest machine, and the physical computer it runs on is the host machine. One physical machine can run multiple virtual machines, each with its own operating system and applications, separate from each other.
What is the Java Virtual Machine?
In languages like C and C++, code is compiled into platform-specific machine code, making them compiled languages. Conversely, languages like JavaScript and Python are interpreted, meaning the computer executes the instructions directly without prior compilation.
Java employs a hybrid approach. Java code is first compiled into bytecode, producing a class file. This class file is then interpreted by the JVM for the underlying platform. The same class file can be executed on any JVM, regardless of the platform or operating system.
Similar to virtual machines, the JVM creates an isolated environment on a host machine, allowing Java programs to run independently of the platform or operating system.
JDK, JRE, and JVM Relationship
JDK (Java Development Kit) | Development Tools + JRE |
JRE (Java Runtime Environment) | Runtime Libraries + JVM |
JVM (Java Virtual Machine) | Bytecode Verifier, Interpreter, JIT Compiler |
Development Tools:
javac
(compiler),java
(runtime),jar
(archiver),javadoc
(documentation generator), debugger, etc.Runtime Libraries: Class libraries for Java API (e.g.,
java.lang
,java.util
,javax.swing
).
How Is Java Platform-Independent?
Java achieves platform independence through bytecode.
Source code (.java files) is compiled into bytecode.
Bytecode can be executed on any platform with a compatible JVM.
Each platform has its own JVM implementation.
How Java Works Internally
Compilation: Java source code (.java files) is compiled by the Java compiler (javac) into bytecode (.class files). Bytecode is a platform-independent code that can be executed on any system with a JVM.
Class Loader: The class loader loads the compiled bytecode into the JVM. It verifies the bytecode to ensure it adheres to Java's security constraints.
Bytecode Verification: The bytecode verifier verifies that byte codes are valid or not without breaching any of Java’s security rules. It gives special attention to checking the type of all the variables and expressions in the code. Bytecode verifier ensures that there is no unauthorized access to memory. Once the code is successfully verified, it is transferred to Java Virtual Machine (JVM) for interpretation.
Note: We can elect to disable the bytecode verifier (which will make it run slightly faster), enable it only for code that is downloaded remotely from the network, or enable it for all the code.
Execution: The JVM interprets the bytecode or uses Just-In-Time (JIT) compilation to convert the bytecode into native machine code for execution. The JIT compiler improves performance by compiling bytecode into native code at runtime.
Garbage Collection: Java's automatic garbage collection manages memory by reclaiming memory used by objects that are no longer referenced, ensuring efficient memory management.
Summary
Compilation: .java to .class (bytecode)
Class Loading: Load bytecode into JVM
Bytecode Verification: Security checks
Execution: Interpretation or JIT compilation
Garbage Collection: Automatic memory management
JDK (Java Development Kit)
Java Development Kit (JDK) is Kit which provides the environment to develop and execute(run) the Java program. JDK is a kit (or package) which includes two things:
Development Tools(to provide an environment to develop your java programs)
JRE (to execute your java program).
Features of JDK:
JDK includes all features that JRE has.
It contains development tools such as a compiler, debugger, etc.
JDK provides the environment to develop and execute Java source code.
It can be installed on Windows, Unix, and Mac operating systems.
The JDK is essential for Java development, providing tools for:
Developing
Compiling
Running Java programs
In short, JDK = JRE + JVM.
The Java Compiler (javac)
The Java compiler, commonly known as javac
, is a tool in the Java development process. It translates human-readable Java source code (written in .java files) into platform-independent bytecode (stored in .class files). This bytecode can then be executed by the Java Virtual Machine (JVM).
Key points about javac
:
Location and Installation:
The
javac
executable is part of the Java Development Kit (JDK), which you need to install on your system.By default,
javac
is located in the/bin
directory of your JDK installation.
Compilation Process:
When you write Java code in a
.java
file, it contains classes, methods, and other constructs.To transform this source code into bytecode, you run
javac
on the.java
files.The compiler performs syntax checking, type checking, and generates corresponding
.class
files.
Usage:
For compiling a single
.java
file, you can use the following command:javac MyClass.java
For multiple files, create a text file (e.g.,
MyFile
) that lists all the Java files you want to compile. Each file should be on a separate line:E:\MyClass1.java E:\MyClass2.java E:\MyClass3.java
Then compile using:
javac @MyFile
Example:
Suppose you have three Java files:
MyClass1.java
,MyClass2.java
, andMyClass3.java
.Create a file named
MyFile
with the content:E:\MyClass1.java E:\MyClass2.java E:\MyClass3.java
Open a command prompt, navigate to the appropriate directory, and execute:
javac @MyFile
Output:
After successful compilation, you’ll find corresponding
.class
files for each.java
file.These
.class
files contain the bytecode that can be executed by the JVM.
Java Disassembler (javap)
javap
is a tool that allows you to peek inside compiled Java class files. It disassembles bytecode—those cryptic instructions that the Java Virtual Machine (JVM) executes—and reveals the underlying structure of classes and their methods. Think of it as a way to see what’s going on behind the scenes in your Java code.
The javap command disassembles class files.
Output depends on the options used.
Without options, javap prints package, protected, and public fields/methods of the classes passed to it.
Basic Usage
When you run javap
without any options, it provides information about the package, protected, and public fields and methods of the specified classes. Here’s the basic syntax:
javap [options] classes...
options
: Specifies various command-line options (more on those shortly).classes...
: One or more classes separated by spaces. You can specify classes by their file names, URLs, or fully qualified class names.
Common Options
Let’s explore some commonly used options:
-v
(or-verbose
): Prints additional information about the selected class. This includes details like constant pool entries, access flags, and method signatures.-l
: Shows line and local variable tables, which can be helpful for debugging.-c
: Prints disassembled code—the actual bytecode instructions—for each method in the class.-s
: Displays internal type signatures.-constants
: Reveals static final constants defined in the class.-sysinfo
: Shows system information (path, size, date, MD5 hash) of the class being processed.
Example:
Let’s say we have a simple class called HelloWorldFrame
:
import java.awt.Graphics;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class HelloWorldFrame extends JFrame {
String message = "Hello World!";
public HelloWorldFrame() {
setContentPane(new JPanel() {
@Override
protected void paintComponent(Graphics g) {
g.drawString(message, 15, 30);
}
});
setSize(100, 100);
}
public static void main(String[] args) {
HelloWorldFrame frame = new HelloWorldFrame();
// Other logic here...
}
}
To disassemble this class, you’d run:
javap -c HelloWorldFrame
And you’d see the disassembled bytecode for each method.
Java Documentation (javadoc)
- javadoc generates documentation from comments in the source code, providing information about classes and methods.
How Does It Work?
Writing Javadoc Comments:
To use JavaDoc, you need to sprinkle your source code with special comments. These comments start with
/**
and end with*/
.Place these comments immediately before a class, method, constructor, or field declaration.
Inside these comments, you can describe what the class or method does, its parameters, return values, and any other relevant details.
Generating the Documentation:
Once you’ve adorned your code with those lovely comments, it’s time to summon the JavaDoc genie.
Use the
javadoc
command (yes, it’s a command-line wizard) to work its magic. Run it against your source files, and it’ll conjure up a beautiful HTML documentation.The generated documentation includes class overviews, method details, and even hyperlinks to related documents. It’s like a well-organized library for your code!
Example:
Let’s say you have a class called AwesomeCalculator
with a method addNumbers(int a, int b)
.
/**
* The AwesomeCalculator class provides basic arithmetic operations.
*/
public class AwesomeCalculator {
/**
* Adds two integers.
*
* @param a The first integer.
* @param b The second integer.
* @return The sum of a and b.
*/
public int addNumbers(int a, int b) {
return a + b;
}
}
Run javadoc
on this, and it’ll create a neat HTML page explaining your AwesomeCalculator
class and its addNumbers
method.
Java Debugger (jdb)
jdb is a simple command-line debugger for Java classes. It’s part of the Java Platform Debugger Architecture (JPDA) and provides inspection and debugging capabilities for both local and remote Java Virtual Machines (JVMs). Whether you’re hunting down pesky bugs or exploring the inner workings of your Java code, jdb has your back.
- jdb is a debugger for Java classes, allowing code inspection and debugging during execution.
Starting a jdb Session
There are a couple of ways to start a jdb session:
Launching a New JVM:
The most common approach is to have jdb launch a new JVM with the main class of the application you want to debug. You can do this by substituting the
jdb
command for thejava
command in your terminal. For example:jdb MyClass
When started this way, jdb calls a second JVM, loads the specified class, and stops execution before the class’s first instruction.
Attaching to an Existing JVM:
If your application is already running, you can attach jdb to it. First, start your JVM with the appropriate debugging options (usually using the
-agentlib:jdwp
flag). For example:java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n MyClass
Then, attach jdb to the running JVM:
jdb -attach 8000
Here,
8000
is the address of the running JVM.
Other Handy Commands
Clearing Breakpoints:
clear MyClass:45
Removes the breakpoint set at line 45 of
MyClass
.Stepping Through Code:
Use
step
to move to the next line of code.next
steps over the current line.cont
continues execution until the next breakpoint.
Inspecting Variables:
print myVariable
displays the value ofmyVariable
.locals
lists all local variables in the current scope.
JRE (Java Runtime Environment)
Java Runtime Environment (JRE) is an installation package which provides environment to only run(not develop) the java program(or application) onto your machine. JRE is only used by them who only wants to run the Java Programs i.e. end users of your system.
JRE consists of the following main components that are as follows:
Java API (Application Programming Interface)
JVM (Class Loader + Bytecode verifier + Interpreter + JIT)
JRE includes:
JVM (Java Virtual Machine):
Executes Java bytecode.
Interprets and runs compiled Java programs.
Ensures platform independence by executing bytecode on any compatible JVM.
Class Libraries (rt.jar):
Contains core Java classes and APIs.
Includes classes for data structures, I/O, networking, GUI, and more.
Provides essential functionality for Java programs.
Other Supporting Libraries (External JARs):
- Additional libraries extending Java's capabilities, such as JDBC drivers (e.g., ojdbc.jar for database connectivity).
In short, JRE = JVM + class libraries (rt.jar) + other libraries (if any).
What is Java API (Application Interface Programming)?
Java Application Programming Interface (API) is a very large collection of prepackaged, ready-made software components that provides the core functionality of the Java programming language.
In simple words, Java API is a large collection of already defined classes, interfaces, and methods in the form of Java packages.
It provides many useful capabilities, such as Graphical User Interface (GUI), Date, Time, and Calendar capabilities to programmers.
JVM (Java Virtual Machine)
Java Virtual machine(JVM) is an abstract virtual machine. It is called a virtual machine because it doesn't physically exist. It is a specification that provides a runtime environment in which Java bytecode can be executed. It can also run those programs which are written in other languages and compiled to Java bytecode.
Features of JVM:
Load the code into memory.
Verifies the code.
Executes the code
Provides runtime environment.
JVM comes with JIT(Just-in-Time) compiler that converts Java source code into low-level machine language. Hence, it runs more faster as a regular application.
As you can observe in the above figure, JVM contains the following main components that are as follows:
Component | Description |
Class Loader Subsystem | Loads, links, and initializes classes. |
Runtime Data Areas | Memory areas for storing program data, including the method area, heap, Java thread stacks, PC registers, and native thread stacks. |
Execution Engine | Executes bytecode and includes the JIT compiler. |
Native Method Interface (JNI) | Enables interaction with native code written in languages like C or C++. |
Native Libraries | Platform-specific libraries for native operations. |
JVM Architecture
The JVM comprises three main components:
Class Loader
Runtime Memory/Data Area
Execution Engine
1. Class Loader Subsystem of JVM
The class loader is responsible for loading Java classes into memory during runtime.
What is Class Loader in Java?
When we write a program in java, the program is placed in memory by the class loader before it can be executed.
Java Class loader takes .class file containing bytecode and transfers it to the memory. It loads the .class file from a disk on your system or over a network.
After loading of class, it is passed to the bytecode verifier.
When you compile a
.java
source file, it gets converted into bytecode (a.class
file). When you use this class in your program, the class loader loads it into the main memory.The first class to be loaded is typically the one containing the
main()
method.The class loading process involves three phases: loading, linking, and initialization.
Class Loading, Linking, and Initialization
1. Class Loading
When we write a program in java, the program is placed in memory by the class loader before it can be executed.
There are basically three subcomponents of Class loader in Java. They are as follows:
Bootstrap class loader
Extensions class loader
System class loader
Types of Class Loaders
Type | Description |
Bootstrap Class Loader | Loads core Java classes, such as those in the java.lang package. These classes are typically located in the rt.jar file. |
Extension Class Loader | Loads classes from the lib/ext directory or any other directory specified by the java.ext.dirs system property. These classes extend the functionality of core Java classes. |
Application Class Loader | Also known as the System Class Loader, loads classes from the classpath specified by the CLASSPATH environment variable or the -classpath command-line option. This is the default class loader for most user-defined classes. |
Delegation Model:
Class loaders follow a delegation model:
Application Class Loader delegates to Extension Class Loader
Extension Class Loader delegates to Bootstrap Class Loader
If a class is not found, the process reverses
When you run a Java program, the JVM starts by loading the main class (specified on the command line). The class loader hierarchy ensures that classes are loaded in a parent-child relationship.
Summary
Bootstrap Class Loader
The root class loader
Loads core Java classes (e.g., java.lang, java.util)
These classes are part of the Java runtime environment
Typically found in the rt.jar file
Extension Class Loader
A subclass of the Bootstrap Class Loader
Loads extension classes
Classes are loaded from the lib/ext directory
Application Class Loader
Also known as the system class loader
Loads classes from the classpath
Responsible for loading user-defined classes
2. Linking
After class loading, the JVM performs linking, which consists of three steps:
Verification: The JVM checks the bytecode for structural correctness. It ensures that the class adheres to Java’s rules (e.g., no illegal access modifiers, valid method signatures, etc.). If verification fails, a
VerifyError
is thrown.Preparation: During this phase, memory is allocated for static fields, and they are initialized with default values (e.g.,
int
fields are set to 0,boolean
fields tofalse
, etc.). This step happens before any explicit initialization.Resolution: Symbolic references (e.g., method calls, field accesses) are resolved to actual references. For example, if a class refers to another class, the JVM resolves the reference to the actual class.
3. Initialization
Initialization is the final step in the class loading process. It involves executing the <clinit>
(class initialization) method, which corresponds to static initializers and static blocks in the source code. Here’s what happens:
Static variables are assigned their explicit values (if any).
Static blocks are executed.
Constructors are called (if an instance is being created).
For example:
public class ExampleClass {
private static final int number = 42;
static {
System.out.println("Static block executed!");
}
public static void main(String[] args) {
System.out.println("Main method called.");
}
}
The number
variable is set to 42 during preparation. The static block prints "Static block executed!" during initialization. When you run the program, the main method is called.
2. Runtime Data Areas of JVM
The JVM divides memory into several runtime data areas:
Area | Description |
Method Area | Stores class data (fields, constant pool, method information) |
Heap | Stores all objects in the JVM, including arrays |
Java Thread Stacks | Each thread has its own stack for local variables, parameters, and return addresses |
PC Registers | Holds address of current and next instruction |
Native Thread Stacks | Contains information related to the native platform |
3. Execution Engine of JVM
The Execution Engine contains:
A virtual processor.
Interpreter: Reads bytecode stream and executes instructions.
Just-In-Time (JIT) compiler: Improves performance by compiling parts of the bytecode with similar functionality simultaneously, reducing compilation time. Here, "compiler" refers to a translator from the instruction set of a Java virtual machine (JVM) to the instruction set of a specific CPU.
JIT (Just-In-Time) Compiler
The Just-In-Time (JIT) compiler is a critical component of the Java Virtual Machine (JVM) that significantly enhances the execution speed of Java programs.
Components of a Just-In-Time (JIT) Compiler
Component | Description |
Intermediate Code Generator | Converts bytecode into an intermediate representation that is easier to optimize. |
Code Optimizer | Applies various optimizations to the intermediate code to improve performance, such as inlining, constant folding, and loop unrolling. |
Target Code Generator | Translates the optimized intermediate code into machine-specific code. |
Profiler | Identifies frequently executed code sections (hotspots) that are suitable for compilation. |
Register Allocator | Assigns registers to variables and temporary values. |
Instruction Scheduler | Rearranges instructions for better performance, such as reducing dependencies or improving cache utilization. |
Garbage Collector Interface | Interacts with the garbage collector to ensure memory management during compilation and execution. |
1. Intermediate Code Generator
Converts bytecode into an easier-to-optimize intermediate representation.
2. Code Optimizer
Applies various optimizations to improve performance:
Inlining
Constant folding
Loop unrolling
3. Target Code Generator
Translates optimized intermediate code into machine-specific code.
4. Profiler
Identifies frequently executed code sections (hotspots) suitable for compilation.
5. Register Allocator
Assigns registers to variables and temporary values.
Register 1 | Variable A |
Register 2 | Temp Value |
Register 3 | Variable B |
6. Instruction Scheduler
Rearranges instructions for better performance:
Reduces dependencies
Improves cache utilization
7. Garbage Collector Interface
Interacts with the garbage collector to ensure proper memory management during compilation and execution.
Key Functions of the JIT Compiler:
Dynamic Translation: The JIT compiler translates Java bytecode into native machine code during runtime, enabling faster execution.
Hotspot Optimization: It identifies frequently executed code segments (hotspots) and optimizes them for better performance.
Collaboration with Interpreter: The JIT compiler works in tandem with the Java interpreter to execute the program efficiently.
Execution Process:
Class Loading: When a
.class
file is loaded into memory, the JVM determines which parts of the code should be interpreted and which should be compiled by the JIT compiler.Bytecode Translation: The JIT compiler translates the selected bytecode instructions into native machine code.
Execution: The translated machine code is executed, often resulting in faster performance compared to interpreted code.
Hotspots Optimization:
Hotspots are code segments that are executed frequently.
The JIT compiler focuses on optimizing these hotspots to improve overall execution time. By dynamically analyzing the program's behaviour, the JIT compiler can apply various optimization techniques, such as inlining methods and eliminating redundant code, to enhance performance.
Disabling JIT:
Although not recommended, the JIT compiler option can be turned off.
However, doing so is generally not recommended, as it can negatively impact the program's performance. Disabling the JIT compiler forces the JVM to rely solely on interpretation, which is typically slower.
Garbage Collector (GC):
- The JVM's garbage collector cleans up unused memory, enhancing overall program efficiency.
JIT compiler dynamically adapts to the program's behaviour, optimizing execution based on actual usage patterns.
Garbage Collector
Clears unused objects from the heap, reclaiming space.
Ensures efficient memory management by identifying and collecting unreachable objects.
Interpreter
- Reads and executes bytecode instructions line by line.
Native Method Libraries of JVM
The Native Method Interface (JNI) connects the JVM with native method libraries for executing native methods.
For example, on Windows, the JNI connects the JVM with Windows native method libraries for platform-specific operations.
Java Native Interface (JNI)
The JNI allows writing Java native methods when an application cannot be purely written in Java.
It bridges Java and native code (e.g., C or C++), enabling platform-specific functionality integration.
JVM Heap Memory (HotSpot Heap Structure)
The JVM heap memory is where objects are allocated and managed during execution. It consists of several regions:
Young Generation: Divided into:
Eden Space: Initial allocation area for new objects.
Survivor Spaces (S0 and S1): Objects surviving minor garbage collections move between these spaces.
Old Generation (Tenured Space): Contains long-lived objects that have survived multiple minor garbage collections.
Permanent Generation (PermGen): Deprecated in Java 8 and removed in Java 9, used to store class and method metadata.
Metaspace (Java 8+): Replaces PermGen, storing class metadata, method information, and reflective data.
Minor, Major, and Full Garbage Collection in JVM
Minor GC (Young Generation Collection): Cleans up the Young Generation (Eden and survivor spaces). Frequent but fast, promoting surviving objects to the Old Generation.
Major GC (Old Generation Collection): Cleans up the Old Generation. Less frequent but slower, causing longer pauses.
Full GC (Full Collection): Cleans the entire heap (Young + Old Generations). Rare and time-consuming, leading to significant application pauses.
JDK vs. JRE vs. JVM
JDK | JRE | JVM |
The full form of JDK is Java Development Kit. | The full form of JRE is Java Runtime Environment. | The full form of JVM is Java Virtual Machine. |
JDK is a software development kit to develop applications in Java. | It is a software bundle which provides Java class libraries with necessary components to run Java code. | JVM executes Java byte code and provides an environment for executing it. |
JDK is platform dependent. | JRE is also platform dependent. | JVM is platform-independent. |
It contains tools for developing, debugging, and monitoring java code. | It contains class libraries and other supporting files that JVM requires to execute the program. | Software development tools are not included in JVM. |
It is the superset of JRE | It is the subset of JDK. | JVM is a subset of JRE. |
The JDK enables developers to create Java programs that can be executed and run by the JRE and JVM. | The JRE is the part of Java that creates the JVM. | It is the Java platform component that executes source code. |
JDK comes with the installer. | JRE only contain environment to execute source code. | JVM bundled in both software JDK and JRE |
Conclusion
🔍 Java Virtual Machine (JVM): The heart of Java's platform independence. It interprets Java bytecode, allowing your code to run on any machine with a JVM. Originally designed for Java, it now supports languages like Scala, Kotlin, and Groovy.
💻 Java Development Kit (JDK): The complete toolkit for Java development. It includes the JRE and essential development tools like the compiler (javac
), archiver (jar
), and debugger (jdb
). If you're developing Java applications, the JDK is your best friend.
⚙️ Java Runtime Environment (JRE): The runtime environment for executing Java applications. It includes the JVM and core libraries but lacks development tools. Perfect for end-users who just want to run Java programs.
🔧 How Java Works:
Compilation: Source code (.java) is compiled into bytecode (.class).
Class Loading: Bytecode is loaded into the JVM.
Bytecode Verification: Ensures security and correctness.
Execution: Bytecode is interpreted or JIT-compiled into native code.
Garbage Collection: Automatic memory management.
🌐 Platform Independence: Java's bytecode can run on any platform with a compatible JVM, making it truly platform-independent.
🛠️ JVM Architecture: Comprises the Class Loader, Runtime Data Areas, and Execution Engine. The JIT compiler within the Execution Engine optimizes performance by compiling bytecode into native code at runtime.
🗂️ Class Loader: Loads classes into memory, ensuring they adhere to Java's security constraints. It follows a delegation model, starting with the Bootstrap Class Loader, then the Extension Class Loader, and finally the Application Class Loader.
🧠 JIT Compiler: Enhances performance by dynamically translating bytecode into machine code during execution. It focuses on optimizing frequently executed code segments (hotspots).
♻️ Garbage Collection: Manages memory by reclaiming space used by objects that are no longer referenced, ensuring efficient memory usage.
🔍 Tools in JDK:
javac: Compiles Java source code into bytecode.
javap: Disassembles class files to reveal bytecode.
javadoc: Generates documentation from comments in the source code.
jdb: A command-line debugger for Java classes.
📊 JDK vs. JRE vs. JVM:
JDK: Development tools + JRE
JRE: Runtime libraries + JVM
JVM: Bytecode verifier, interpreter, JIT compiler
The JVM provides platform independence, making Java versatile and allowing code to be written once and run anywhere. The JRE offers the environment needed to execute Java applications, while the JDK provides the tools to create, compile, and debug Java programs. By understanding how these components work, developers can better optimize their applications and fully utilize the Java platform. Whether you're developing in Java or any other JVM language, knowing these tools will improve your programming efficiency and effectiveness.The Java tutorial page lists down all the important topics you can go through to get a deeper understanding of the language basics and advanced concepts.
Subscribe to my newsletter
Read articles from Dilip Patel directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Dilip Patel
Dilip Patel
Software Developer