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?
- Platform Independence: Same .class file runs on any JVM
- Security: Bytecode verifier checks for malicious code
- Optimization: JVM can optimize bytecode at runtime (JIT)
- Compactness: Bytecode is more compact than source code
- Verification: Ensures type safety and memory safety
Bytecode Verification
Before execution, the JVM verifies bytecode:
- Format Check: Ensures valid .class file structure
- Type Safety: Verifies type compatibility
- Memory Bounds: Checks array and stack bounds
- 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
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 testsAnalyze 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 spaceApply 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 documentationQuiz
1. What is the output of compiling a .java file?
2. Why can the same .class file run on different operating systems?
3. What is the primary purpose of Compilation and Execution?
4. What is a common mistake when implementing Compilation and Execution?
Flashcards
Question
What command compiles Java source code?
Click to reveal answer
Answer
javac (Java Compiler). Example: javac HelloWorld.java creates HelloWorld.class
Question
What is bytecode?
Click to reveal answer
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?
Click to reveal answer
Answer
Checks bytecode for security violations, type safety, and memory safety before execution.
Question
What is Compilation and Execution?
Click to reveal answer
Answer
Compilation and Execution is a key concept in Java programming.
Question
When to use Compilation and Execution?
Click to reveal answer
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