The Java compilation process has two stages. First, javac compiles your .java source into platform-neutral bytecode in a .class file. Then the JVM loads, verifies and runs that bytecode, interpreting it and compiling hot code to native machine code with the JIT compiler. Comparing Java editions instead? See Java SE vs Java EE vs Java ME.
Why Java Is Platform Independent
Java is known for its platform independence, meaning Java applications can run on any device or operating system.
Here's how it works:
- Compilation — when you compile a Java program, the Java compiler (
javac) converts the source code into bytecode. - JVM — this bytecode is not specific to any type of hardware or operating system. Instead, it is executed by the JVM, which is a platform-dependent component.
- Execution — the JVM reads the bytecode and translates it into native machine code that can be executed directly by the hardware.
It's important to note that while Java itself is platform-independent, the JVM is platform-dependent.
What Actions the JVM Performs
The Java Virtual Machine (JVM) performs a series of actions to run Java applications:
- Class Loading — the JVM loads class files into memory.
- Execution — the JVM's execution engine interprets the bytecode or compiles it into native machine code using the Just-In-Time (JIT) compiler and executes it.
- Runtime Memory Management — the JVM manages and optimizes memory usage during runtime, including the heap for object allocation, the stack for method calls, and the method area for class data and code.
- Garbage Collection — the JVM automatically manages the deletion of objects no longer needed by the application to free up memory resources.
- JVM Instructions — the JVM has instructions for tasks such as load and store, arithmetic operations, type conversion, object creation and manipulation, operand stack management (push/pop), control transfer (branching), and method invocation and return.
Where Java Program Execution Begins (the main() Method)
The execution of Java programs begins with the main() method, which serves as the entry point for the JVM to start the application.
The method must have a specific signature to be recognized by the JVM:
public static void main(String[] args) {
// Code goes here
}
Breaking Down the Signature
- public — an access specifier that allows the JVM to access the method.
- static — indicates the method can be called without creating an instance of the class.
- void — specifies that the method does not return any value.
- main — the name of the method the JVM looks for as the starting point.
- String[] args — an array of Strings that can store command-line arguments passed to the program.
If the main() method is missing or incorrectly defined, the JVM will not execute the program and will throw an error.
Which Name the Compiler Checks
In Java, the compiler does not execute the program—it only compiles the source code into bytecode.
The JVM is responsible for executing the compiled bytecode.
When you run a Java program, the JVM looks for the main() method in the class you specify and starts execution from there.
To execute a program, you use the java command followed by the class name; the class name should be the name of the class containing the main() method, without the .class extension.
The JVM then looks for the public static void main(String[] args) method in that class and begins execution from that point.
Which Name the JVM Checks After Compiling
After a Java program is compiled, the JVM checks the name of the main class when executing the program.
The main class is the one that contains the main() method (the application's entry point).
The JVM uses the class name to locate and load the correct .class file into memory.
During execution, the JVM goes through several stages:
- Class Loading — the main class is loaded into memory.
- Bytecode Verification — the bytecode of the loaded class is verified for correctness.
- Just-In-Time Compilation — the bytecode may be compiled to native machine code for better performance.
Executing Code Before the main() Method (Static Blocks)
Yes, you can execute code before the main() method using a static block.
A static block is a group of statements that gets executed only once when the class is loaded into memory by the Java ClassLoader—also known as a static initialization block.
It runs before any object is created and even before main() runs.
class StaticBlock_EX {
static {
System.out.println("class without a main method");
System.exit(0);
}
}
Why a Static Block Works Before main()
The JVM loads the class, executes all static initializers while loading, and only after that calls the main() method.
Note on Java Versions
The example above (running without a main() method) works up to Java 1.6.
Java 7 and newer versions don't allow this because the JVM checks for the presence of the main() method before initializing the class. We confirmed it on Java 21: the static block never printed, and the JVM stopped with "Error: Main method not found in class NoMain, please define the main method as: public static void main(String[] args)".
Use Cases in Real Projects
- Initializing configuration or environment variables.
- Loading log files (Log4j, ExtentReports).
- Setting WebDriver system properties.
- Pre-loading heavy static data before test execution.
Static blocks execute only once per class load.
Real-Life Example
When you turn on your mobile, the system first loads essential startup programs before showing the home screen—the same way Java loads static blocks before the main() method.
Real-Time Testing Example
In automation frameworks, a static block can load configuration files, initialize loggers, or set system properties before test execution begins.
Can the Filename and Class Name Be the Same?
Yes—in Java, it is common convention to have the filename and the public class name match.
The Rules
- If the class is
public, the filename must match the class name exactly, including case sensitivity (e.g., a public classMyClassmust be inMyClass.java). - If there is no
publicclass in the file, the filename can differ from the class names inside the file (e.g., you can name itMyProgram.java), but it's still good practice to match the filename to the class name for clarity and maintainability.
See It Run
public class Launcher {
static {
System.out.println("1. static block runs when the class is loaded");
}
public static void main(String[] args) {
System.out.println("2. main() runs next");
System.out.println("Java version: " + System.getProperty("java.version"));
System.out.println("OS: " + System.getProperty("os.name") + " / " + System.getProperty("os.arch"));
}
}
$ javac Launcher.java # compiler: source → Launcher.class (bytecode)
$ java Launcher # JVM: loads the class, runs the static block, then main()
1. static block runs when the class is loaded
2. main() runs next
Java version: 21.0.10
OS: Linux / amd64
The same Launcher.class runs unchanged on Windows or macOS — only the OS line changes, because each platform has its own JVM. That is platform independence in one command. Two more experiments we ran:
- Filename rule: a file
Wrong.javacontainingpublic class Helperfails to compile with "class Helper is public, should be declared in a file named Helper.java". - Several classes in one file: a file
Two.javawith non-public classesAlphaandBetacompiles intoAlpha.classandBeta.class, andjava Betaruns Beta'smain()— the JVM looks for the class name, not the file name.
Shortcut since Java 11: java Launcher.java compiles in memory and runs a single-file program in one step — handy for practice programs. Newer releases also simplify the entry point for small programs (for example, a plain void main()), but public static void main(String[] args) remains the standard form that frameworks, IDEs and interviewers expect.
Step through the order of execution — class loading, the static block, then main() — in the Java Code Visualizer.
From Real Projects
Java has been the language of every automation framework I've worked with — Selenium, TestNG, POM classes and Apache POI for Excel data. Interviews for automation roles regularly include basic programs like this one, often followed by a question on OOP concepts. Practice writing it by hand and explaining how you'd test it. On Canolog, the many forms and screens across sales, inventory, finance and service are where keeping page details in POM classes and reusable steps in a business library paid off. Knowing that the same compiled classes run on any JVM explains why one test framework can run on every machine in the team.
Current JDK Version
The JDK version used throughout these tutorials is 17.
(Newer LTS releases such as Java 21 are also widely used — everything on this page applies to them too.)
📚 Official documentation: dev.java: Learn Java (Oracle) · Java 21 API documentation
The Java Compilation Process Step by Step
Hello.java (source code you write)
|
| javac Hello.java compile time
v
Hello.class (bytecode, same on every OS)
|
| java Hello run time, inside the JVM
v
Class Loader -> Bytecode Verifier -> Interpreter + JIT compiler
|
v
native machine code for this OS/CPU
- Write the source in
Hello.java. - Compile with
javac Hello.java. The compiler checks syntax and types and writesHello.class. Compile errors stop here. - Load: running
java Hellostarts the JVM, and the class loader readsHello.classplus every class it uses. - Verify: the bytecode verifier checks the code is safe and well-formed before anything runs.
- Execute: the interpreter runs the bytecode, and the JIT compiler turns frequently used methods into native code for speed.
Since Java 11 you can skip the separate compile step for a single file with java Hello.java; the JVM compiles it in memory and runs it. Under the hood it's still the same two stages.
FAQs
1. Why is the Java platform independent?
Because javac compiles source code into hardware-neutral bytecode, which any platform's JVM translates into native machine code—so the same bytecode runs anywhere, even though the JVM itself is platform-dependent.
2. What actions does the JVM perform?
- Class loading
- Execution (interpretation or JIT compilation)
- Runtime memory management
- Garbage collection
- Executing JVM instructions
3. From which method does Java execution begin?
From public static void main(String[] args), the entry point the JVM looks for; if it's missing or incorrectly defined, the JVM throws an error.
4. How can you execute code before the main() method?
Using a static (initialization) block, which runs once when the class is loaded—before any object is created and before main().
5. Does the compiler execute the program?
No—the compiler only produces bytecode; the JVM executes it by locating the main() method in the specified class.
6. Can the filename and class name be the same?
Yes, and if the class is public, the filename must match the class name exactly (case-sensitive); otherwise, the filename can differ, though matching is good practice.
7. What is the Java compilation process?
The compiler javac converts .java source into bytecode in a .class file. The JVM then loads, verifies and executes that bytecode, using an interpreter and a JIT compiler to produce native machine code.
8. What is the difference between JDK, JRE and JVM?
The JVM runs bytecode. The JRE is the JVM plus the standard class libraries needed to run programs. The JDK is the JRE plus development tools such as javac and jar. To write and compile code, install the JDK.
9. What does the JIT compiler do in Java?
The Just-In-Time compiler watches which methods run often and compiles them from bytecode into native machine code while the program runs, so hot code runs much faster than it would if it were only interpreted.