The main()
method is the entry point of any standalone Java application and plays a crucial role in the JVM execution process. Here’s why it’s significant:
1. JVM Execution Process and main()
When you execute a Java program using the java
command, the JVM performs the following steps:
- Class Loading
- The JVM loads the class that contains the
main()
method. - It uses the ClassLoader to find and load the
.class
file into memory.
- The JVM loads the class that contains the
- Bytecode Verification
- The JVM verifies the class bytecode for security and correctness.
- It ensures there are no violations like illegal access to memory.
- JIT Compilation & Interpretation
- The Java Just-In-Time (JIT) compiler compiles bytecode into native machine code for execution.
- Alternatively, the Interpreter executes bytecode line-by-line if JIT hasn’t optimized it yet.
- Calling
main()
- The JVM searches for the
main()
method with the exact signature:javaCopyEdit
- The JVM searches for the
public static void main(String[] args)
If found, execution begins from main()
.If not found, the JVM throws:
Error: Main method not found in class <classname>
The main thread is created and starts executing main()
.
2. Why Must main()
Have This Signature?
public static void main(String[] args)
public
→ The JVM needs to call main()
from outside the class.
static
→ The JVM does not create an instance of the class before calling main()
.
void
→ The method does not return anything to the JVM.
String[] args
→ Allows command-line arguments to be passed to the program.
3. JVM and main()
in a Multi-Threaded Environment
The JVM creates the main thread to run the main()
method.
If the program creates additional threads (Thread
, ExecutorService
, etc.), they execute alongside main()
.
When the main()
method completes, the JVM will only terminate if no other non-daemon threads are running.
4. Can We Have main() Without String[] args?
No, the JVM expectsmain(String[] args)
.If you write:
public static void main() { }
The JVM will not recognize it and throw an error.
5. Can We Overload main()
?
Yes, you can overload main()
, but the JVM will only invoke the one with the correct signature:
public class Example {
public static void main(String[] args) {
System.out.println("Main method called!");
}
public static void main(int num) { // Overloaded main()
System.out.println("Overloaded main: " + num);
}
}
If you run java Example
, only main(String[] args)
will execute.
6. Can We Call main()
Manually?
Yes, you can call main()
like a regular method:
public class Example {
public static void main(String[] args) {
System.out.println("Main method called!");
main(new String[]{"Hello"});
}
}
However, this is just a normal method call; the JVM will not treat it as the program entry point.
Conclusion
- The
main()
method acts as the starting point for the JVM execution. - The JVM loads the class, verifies bytecode, and starts execution from
main()
. - The correct signature is required, or the JVM throws an error.
- The main thread starts with
main()
, and the JVM keeps running while non-daemon threads exist.
JVM Execution Flow
+--------------------+
| Java Source Code | (e.g., MyProgram.java)
+--------------------+
|
| (Step 1: Compilation)
v
+--------------------+
| Java Compiler | (javac MyProgram.java)
+--------------------+
|
| Generates Bytecode (.class file)
v
+--------------------+
| Bytecode (.class) |
+--------------------+
|
| (Step 2: Execution Begins)
v
+----------------------+
| JVM Invokes main() | (java MyProgram)
+----------------------+
|
| (Step 3: Class Loading)
v
+----------------------+
| Class Loader |
| - Loads .class file |
| - Resolves dependencies |
+----------------------+
|
| (Step 4: Bytecode Verification)
v
+----------------------+
| Bytecode Verifier |
| - Ensures no unsafe code |
| - Checks for integrity |
+----------------------+
|
| (Step 5: Runtime Execution)
v
+----------------------+
| JVM Execution Engine |
| - Interpreter (Executes line-by-line) |
| - JIT Compiler (Optimizes for speed) |
+----------------------+
|
| (Step 6: Native Code Execution)
v
+----------------------+
| CPU Executes Code |
+----------------------+
|
| (Step 7: Garbage Collection & Cleanup)
v
+----------------------+
| Memory Management |
| - Garbage Collector |
| - Reclaims unused memory |
+----------------------+
Detailed Explanation of the Execution Flow
- Source Code (
.java
File)- The programmer writes Java code in a
.java
file.
- The programmer writes Java code in a
- Compilation (
javac
)- The Java Compiler (
javac
) converts the.java
file into bytecode (.class
file).
- The Java Compiler (
- Class Loading
- The Class Loader loads the bytecode into memory.
- It resolves dependencies and finds referenced classes.
- Bytecode Verification
- The Bytecode Verifier checks for:
- Security violations
- Invalid memory access
- Illegal bytecode instructions
- The Bytecode Verifier checks for:
- Execution Engine
- The JVM Execution Engine processes bytecode in two ways:
- Interpreter: Translates bytecode line-by-line (slow but starts execution quickly).
- JIT (Just-In-Time) Compiler: Converts frequently used bytecode into native machine code for better performance.
- The JVM Execution Engine processes bytecode in two ways:
- Native Code Execution
- The optimized native code runs on the CPU.
- Garbage Collection & Cleanup
- The Garbage Collector (GC) reclaims unused memory.
- Memory management ensures efficient resource utilization.
How main()
Fits in the Execution
- The JVM searches for the
main()
method in the loaded class. - If found, execution starts in the main thread.
- If
main()
is missing, an error occurs:
Error: Main method not found in class MyProgram