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.


Advertisement

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 class MyClass must be in MyClass.java).
  • If there is no public class in the file, the filename can differ from the class names inside the file (e.g., you can name it MyProgram.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.java containing public class Helper fails to compile with "class Helper is public, should be declared in a file named Helper.java".
  • Several classes in one file: a file Two.java with non-public classes Alpha and Beta compiles into Alpha.class and Beta.class, and java Beta runs Beta's main() — 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
  1. Write the source in Hello.java.
  2. Compile with javac Hello.java. The compiler checks syntax and types and writes Hello.class. Compile errors stop here.
  3. Load: running java Hello starts the JVM, and the class loader reads Hello.class plus every class it uses.
  4. Verify: the bytecode verifier checks the code is safe and well-formed before anything runs.
  5. 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.