Skip to main content

Command Palette

Search for a command to run...

Java Two-step execution process:

Published
•3 min read•View as Markdown

Java is a platform-independent language that follows a two-step execution process:

  • Compilation (source code -> bytecode)

  • Execution (bytecode -> machine code via JVM)

Compilation in Java

Java source code (.java files) is compiled by the Java Compiler (javac) into Bytecode, stored in .class files. This bytecode is platform-independent and ready to run on any system with a JVM.

Internally, compilation involves:

  1. Parsing: Converts code into syntax trees (AST).

    • The compiler reads your source code (.java file`) and checks the syntax.

    • It then converts the code into a tree-like structure called an Abstract Syntax Tree (AST).

    • This tree represents the logical structure of your program — classes, methods, variables, etc.

      Example: The statement int x = 10; becomes a small tree node, a variable declaration with type int and value 10.

  2. Entering: Populates symbol tables.

    • The compiler records class and member names (like variables, methods, etc.) into a symbol table.

    • Think of it as the compiler’s dictionary — it stores information about what exists and where it is defined.

      Example: It remembers that there’s a class HelloWorld with a main method.

  3. Annotation Processing: Handles annotations.

    • If your code has annotations (like @Override, @Deprecated, @Entity, etc.), this phase processes them.

    • Tools or frameworks can even generate new code or files during this stage.

      Example: @Entity in frameworks like Hibernate gets processed here.

  4. Attribution: Performs type checking and name resolution.

    • The compiler now checks types — ensuring variables, return types, and method calls are valid.

    • It also resolves names — linking each variable or method call to its actual declaration.

      Example: Checks that x is declared before use and that System.out.println() exists.

  5. Flow Analysis: Checks for variable use and reachability.

    • Here, the compiler performs logical checks:

      • Are all variables initialized before use?

      • Is there unreachable code (like code after return)?

    • It ensures your code’s flow makes sense and follows Java rules.

  6. Desugaring: Removes syntactic shortcuts.

    • Java allows shortcuts (syntactic sugar) — for example:

      • for (int i : list) → becomes a normal iterator-based loop internally.

      • var → becomes the actual inferred type.

    • In this stage, the compiler rewrites these shortcuts into simpler, more explicit Java constructs.

  7. Generation: Produces .class files.

    • Finally, the compiler translates the checked and simplified AST into bytecode.

    • The bytecode is stored in .class files — this is what the JVM actually runs.

      So HelloWorld.java → HelloWorld.class.

Execution via JVM

The .class files are executed by the Java Virtual Machine (JVM), which includes the following stages:

  1. Class Loader

    Loads the main class and other dependencies into memory.

    • Primordial Loader: Default system loader.

    • Non-primordial Loader: Custom loaders for advanced control.

Class r = loadClass(String className, boolean resolveIt);

  1. Bytecode Verifier

    Checks that the loaded bytecode is safe to execute. It ensures:

    • Variables are initialized

    • Method signatures are correct

    • Private access rules aren’t violated

    • No stack overflows

  2. Just-In-Time (JIT) Compiler

    Converts bytecode into native machine code at runtime for faster execution.