Skip to content
beginnerPhase 9 · Java Foundations

Compilation and Execution

Understand how Java source code becomes bytecode and runs on the JVM.

30m
0 problems
Topic Progress0%

Compilation Process

Java Compilation Pipeline

Java uses a two-step process: compilation and interpretation.

Source Code (.java) → Compiler (javac) → Bytecode (.class) → JVM → Machine Code

Step 1: Writing Source Code

// HelloWorld.java
public class HelloWorld {
    public static void main(String[] args) {
        System.out.println("Hello, World!");
        
        // Complex logic
        int[] numbers = {1, 2, 3, 4, 5};
        int sum = 0;
        for (int num : numbers) {
            sum += num;
        }
        System.out.println("Sum: " + sum);
    }
}

Step 2: Compilation with javac

# Compile the source file
javac HelloWorld.java

# This creates HelloWorld.class (bytecode)
# The .class file contains platform-independent bytecode

# Compile multiple files
javac *.java

# Compile with dependencies
javac -cp lib/*.jar src/**/*.java

# Compile with warnings
javac -Xlint:all HelloWorld.java

Step 3: Execution with java

# Run the compiled class
java HelloWorld

# Output: Hello, World!

# Run with JVM options
java -Xmx512m HelloWorld
java -Xms256m -Xmx1g HelloWorld

# Run with classpath
java -cp bin:lib/* HelloWorld

# Run main method in a package
java com.amazon.HelloWorld

Compilation Flags

# Generate debugging info
cjavac -g HelloWorld.java

# Suppress warnings
javac -nowarn HelloWorld.java

# Treat warnings as errors
javac -Xlint -Werror HelloWorld.java

# Generate verbose output
javac -verbose HelloWorld.java

# Cross-compile for different Java version
javac --release 11 HelloWorld.java

Compilation Errors vs Runtime Errors

// COMPILATION ERROR - caught by javac
public class CompileError {
    public static void main(String[] args) {
        int x = "not a number";  // Type mismatch
        System.out.println(undeclaredVar);  // Variable not found
    }
}

// RUNTIME ERROR - caught during execution
public class RuntimeError {
    public static void main(String[] args) {
        int[] arr = new int[5];
        System.out.println(arr[10]);  // ArrayIndexOutOfBoundsException
        
        String s = null;
        System.out.println(s.length());  // NullPointerException
    }
}

Understanding Bytecode

What is Bytecode?

Bytecode is an intermediate representation of Java code that the JVM can execute. It's not machine code for any specific CPU - it's designed for the JVM.

Bytecode Structure

.class file format:
┌─────────────────────────┐
│ Magic Number (0xCAFEBABE)│
├─────────────────────────┤
│ Version Info             │
├─────────────────────────┤
│ Constant Pool            │
├─────────────────────────┤
│ Access Flags             │
├─────────────────────────┤
│ This Class               │
├─────────────────────────┤
│ Super Class              │
├─────────────────────────┤
│ Interfaces               │
├─────────────────────────┤
│ Fields                   │
├─────────────────────────┤
│ Methods                  │
├─────────────────────────┤
│ Attributes               │
└─────────────────────────┘

Examining Bytecode

# Use javap to disassemble
cjavap -c HelloWorld.class

# Output shows bytecode instructions:
# public static void main(java.lang.String[]);
#   Code:
#      0: getstatic     #2  // Field java/lang/System.out:Ljava/io/PrintStream;
#      3: ldc           #3  // String Hello, World!
#      5: invokevirtual #4  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
#      8: return

Bytecode Instructions

// Source code
public class BytecodeDemo {
    public static void main(String[] args) {
        int x = 10;
        int y = 20;
        int z = x + y;
        System.out.println(z);
    }
}

// Bytecode equivalent (conceptual):
// iconst_10      // Push constant 10 onto stack
// istore_1       // Store in local variable 1
// iconst_20      // Push constant 20 onto stack
// istore_2       // Store in local variable 2
// iload_1        // Load local variable 1
// iload_2        // Load local variable 2
// iadd           // Add top two values
// istore_3       // Store result in local variable 3
// getstatic      // Get System.out
// iload_3        // Load value to print
// invokevirtual  // Call println

Why Bytecode?

  1. Platform Independence: Same .class file runs on any JVM
  2. Security: Bytecode verifier checks for malicious code
  3. Optimization: JVM can optimize bytecode at runtime (JIT)
  4. Compactness: Bytecode is more compact than source code
  5. Verification: Ensures type safety and memory safety

Bytecode Verification

Before execution, the JVM verifies bytecode:

  1. Format Check: Ensures valid .class file structure
  2. Type Safety: Verifies type compatibility
  3. Memory Bounds: Checks array and stack bounds
  4. Access Control: Enforces visibility rules

Execution Flow

Complete Execution Flow

1. Source Code (.java)
   ↓
2. Compiler (javac)
   ↓
3. Bytecode (.class)
   ↓
4. Class Loader loads bytecode
   ↓
5. Bytecode Verifier checks safety
   ↓
6. Execution Engine interprets/compiles
   ↓
7. Native code execution
   ↓
8. Output

Class Loading Process

// Three phases of class loading:
// 1. Loading: Read .class file into memory
// 2. Linking: Verify, prepare, resolve
// 3. Initialization: Execute static code

public class ClassLoading {
    // Static block runs during initialization
    static {
        System.out.println("Class loaded and initialized");
    }
    
    public static void main(String[] args) {
        // First access triggers class loading
        System.out.println("Main method executed");
    }
}

Dynamic Class Loading

// Load classes at runtime
public class DynamicLoading {
    public static void main(String[] args) throws Exception {
        // Using Class.forName()
        Class<?> clazz = Class.forName("java.lang.String");
        System.out.println("Loaded: " + clazz.getName());
        
        // Using class loader
        ClassLoader loader = DynamicLoading.class.getClassLoader();
        Class<?> loaded = loader.loadClass("java.util.ArrayList");
        
        // Create instance dynamically
        Object obj = clazz.getDeclaredConstructor().newInstance();
    }
}

JVM Execution Modes

# Interpreter mode (default)
java HelloWorld

# Check compilation threshold
java -XX:+PrintCompilation HelloWorld

# Tiered compilation
java -XX:+TieredCompilation HelloWorld

# Aggressive optimization
java -XX:+AggressiveOpts HelloWorld

Performance Monitoring

// Monitor compilation and performance
public class PerformanceMonitor {
    public static void main(String[] args) {
        // Start time
        long startTime = System.nanoTime();
        
        // Run code
        for (int i = 0; i < 1000000; i++) {
            Math.sqrt(i);
        }
        
        // End time
        long endTime = System.nanoTime();
        
        System.out.printf("Execution time: %.3f ms%n", 
            (endTime - startTime) / 1_000_000.0);
        
        // Garbage collection info
        Runtime runtime = Runtime.getRuntime();
        System.out.printf("Used memory: %d MB%n", 
            (runtime.totalMemory() - runtime.freeMemory()) / 1024 / 1024);
    }
}

Common Execution Issues

// Issue 1: Class not found
// java.lang.ClassNotFoundException
// Fix: Check classpath, ensure .class file exists

// Issue 2: Main method not found
// Error: Main method not found in class
// Fix: Ensure public static void main(String[] args)

// Issue 3: Unsupported class version
// java.lang.UnsupportedClassVersionError
// Fix: Compile with compatible Java version

// Issue 4: Stack overflow
class Infinite {
    static void recurse() {
        recurse();  // No base case!
    }
}
// Fix: Add base case to recursion

Platform Independence Demonstrated

// This code runs identically on:
// - Windows
// - Linux  
// - macOS
// - Any other OS with JVM

public class PlatformDemo {
    public static void main(String[] args) {
        // OS-independent operations
        System.out.println("Hello from " + System.getProperty("os.name"));
        
        // File operations (path handling is OS-independent)
        Path path = Paths.get("data", "file.txt");
        System.out.println("Path: " + path);
        
        // But the underlying implementation differs per OS
        // JVM abstracts these differences
    }
}

Practice Problems

0/3solved
Compilation and Execution Implementation

Implement Compilation and Execution in Java. Include proper error handling and follow Java conventions.

Solution
// Java implementation:
// 1. Proper class structure
// 2. Error handling
// 3. JavaDoc comments
// 4. Unit tests
Compilation and Execution Time Complexity

Analyze the time and space complexity of Compilation and Execution operations. Optimize for common use cases.

Solution
// Complexity analysis:
// - Time: depends on implementation
// - Space: consider auxiliary space
// - Trade-offs between time and space
Compilation and Execution Java Best Practices

Apply Java best practices when using Compilation and Execution. Consider immutability, thread safety, and clean code.

Solution
// Best practices:
// 1. Use immutable objects where possible
// 2. Thread-safe implementations
// 3. Proper exception handling
// 4. Resource management (try-with-resources)
// 5. JavaDoc documentation

Quiz

1. What is the output of compiling a .java file?

Question 1 options

2. Why can the same .class file run on different operating systems?

Question 2 options

3. What is the primary purpose of Compilation and Execution?

Question 3 options

4. What is a common mistake when implementing Compilation and Execution?

Question 4 options

Flashcards

Question

What command compiles Java source code?

Answer

javac (Java Compiler). Example: javac HelloWorld.java creates HelloWorld.class

Question

What is bytecode?

Answer

Platform-independent intermediate representation of Java code that the JVM executes. Stored in .class files.

Question

What is the purpose of the bytecode verifier?

Answer

Checks bytecode for security violations, type safety, and memory safety before execution.

Question

What is Compilation and Execution?

Answer

Compilation and Execution is a key concept in Java programming.

Question

When to use Compilation and Execution?

Answer

Use Compilation and Execution when building production systems that require reliability, scalability, and maintainability.

Revision Notes

Key Takeaways

  • 1.javac compiles .java to .class bytecode files
  • 2.Bytecode is platform-independent and runs on any JVM
  • 3.The JVM translates bytecode to platform-specific machine code
  • 4.Class loading happens in three phases: loading, linking, initialization
  • 5.JIT compilation optimizes frequently executed bytecode

Interview Tips

  • Explain the difference between compilation and interpretation
  • Know how to compile and run Java programs from command line
  • Understand why Java is platform-independent
  • Be ready to discuss class loading and bytecode verification

Cheat Sheet

Compilation & Execution Cheat Sheet

Compilation:

javac HelloWorld.java  # Creates HelloWorld.class
javac -cp lib/*.jar src/**/*.java  # With dependencies

Execution:

java HelloWorld  # Run compiled class
java -Xmx512m HelloWorld  # With memory limit
java -cp bin:lib/* HelloWorld  # With classpath

Key Concepts:

  • Source (.java) → Compiler (javac) → Bytecode (.class) → JVM → Machine Code
  • Bytecode is platform-independent
  • JVM translates bytecode to platform-specific code
  • Class loader loads bytecode, verifier checks safety