HSHimanshu Sharma
Basic Java

What is Java? JDK, JRE, JVM, bytecode and your first program

What is Java? JDK, JRE, JVM, bytecode and your first program Advertisement

Java is one of the most widely used programming languages in the world. It powers Android apps, large banking and insurance systems, search and e-commerce back ends, big-data tools and a great deal of enterprise software. It was designed around one promise, "write once, run anywhere": compile a program once and run it on Windows, macOS or Linux without changes. This post explains what Java is, how that promise works through the JVM, how the JDK, JRE and JVM relate, and how to write, compile and run your first program. It is the first of a four-part Java series; the code was compiled and run on OpenJDK 21. If you have not programmed before, read fundamentals of technology first, and note that some familiarity with C helps you appreciate what Java simplifies.

A short history

Java was started in the early 1990s at Sun Microsystems by James Gosling and his team (first under the name Oak), originally for consumer electronics, and was released publicly in 1995. It was designed to look familiar to C and C++ programmers while removing their most dangerous features: explicit pointer arithmetic and manual memory management. Sun was acquired by Oracle in 2010. Since 2017 a new feature release has appeared every six months, and every few years one is designated a long-term support (LTS) release, which receives updates for years. The LTS versions are 8, 11, 17, 21 and 25. Most new learning should use a recent LTS such as 21 or 25.

What makes Java what it is

  • Platform independent: the compiler produces bytecode, not machine code, and a Java Virtual Machine runs it on any operating system (explained below).
  • Object-oriented: almost everything lives inside classes. (See the object-oriented basics in Python for the shared ideas.)
  • Statically typed: every variable has a declared type, and the compiler catches many mistakes before the program runs.
  • Automatic memory management: a garbage collector frees objects that nothing refers to any more, so there is no free.
  • Safe: no pointer arithmetic, array bounds are checked at run time (an out-of-range index throws an exception instead of corrupting memory), and the JVM verifies bytecode before running it.
  • Multithreaded: threads and concurrency tools are built in, as covered in part 3 of the series.
  • A huge ecosystem: a very large standard library, build tools (Maven, Gradle), frameworks (Spring, Jakarta EE) and IDEs.
  • Mostly fast: the JVM's just-in-time (JIT) compiler turns hot bytecode into machine code while the program runs, so long-running Java programs can approach the speed of compiled languages.

JDK, JRE and JVM

These three terms confuse every beginner. They nest inside each other.

Term Full name What it is
JVM Java Virtual Machine the engine that loads and executes bytecode, manages memory and runs the garbage collector. A different JVM exists for each operating system.
JRE Java Runtime Environment the JVM plus the standard class libraries: what you need to run Java programs
JDK Java Development Kit the JRE plus development tools such as javac (the compiler), java (the launcher), javap (the disassembler), jar and a debugger: what you need to write and run Java programs

In short: JDK contains JRE, which contains JVM. As a developer you install the JDK. Since Java 11, Oracle and others stopped shipping a separate JRE download for most users; you run applications with the JDK or with a smaller runtime built by jlink. Many companies provide free, tested builds of the open-source OpenJDK (Eclipse Temurin, Amazon Corretto, Azul Zulu, Microsoft Build of OpenJDK, Oracle OpenJDK); they are all fine for learning.

How "write once, run anywhere" works

A C compiler produces machine code for one specific operating system and CPU. A Java compiler produces bytecode, a compact instruction set for an imaginary computer, the JVM. Each real platform has its own JVM that translates bytecode into the real machine's instructions.

Hello.java  --javac-->  Hello.class (bytecode)  --JVM on Windows--> runs
 (source)                (same file)             --JVM on macOS ---> runs
                                                 --JVM on Linux ---> runs

You can look at the bytecode with the javap tool. For this first program:

public class Hello {
    public static void main(String[] args) {
        System.out.println("Hello, Java!");
    }
}

javap -c Hello printed, for the main method:

public static void main(java.lang.String[]);
  Code:
     0: getstatic     #7    // Field java/lang/System.out:Ljava/io/PrintStream;
     3: ldc           #13   // String Hello, Java!
     5: invokevirtual #15   // Method java/io/PrintStream.println:(Ljava/lang/String;)V
     8: return

Four simple instructions: fetch System.out, push the string constant, call println, return. The same Hello.class file runs on every platform's JVM. This is also why Java is called "compiled and interpreted": it is compiled to bytecode, then the JVM interprets and JIT-compiles it.

Installing Java and running your first program

  1. Download a JDK (21 or 25 LTS) from a provider such as Adoptium (Eclipse Temurin), Amazon Corretto or Oracle, and run the installer. On macOS and Linux, a package manager works too (brew install openjdk, sudo apt install openjdk-21-jdk).
  2. Open a terminal and check:
$ java -version
openjdk version "21.0.5" 2024-10-15 LTS
$ javac -version
javac 21.0.5

If javac is "not found", you have a runtime without the development tools, or the bin folder of the JDK is not on your PATH. On Windows, also set JAVA_HOME to the JDK folder.

  1. Save the program above as Hello.java (the file name must match the public class name exactly, including capital letters), then:
$ javac Hello.java        # creates Hello.class
$ java Hello              # runs it
Hello, Java!

Since Java 11 you can skip the explicit compile step for a single file: java Hello.java compiles it in memory and runs it, and it printed the same greeting. Use it for quick experiments; real projects use a build tool.

Anatomy of the program

  • public class Hello: all Java code lives in classes. public means visible everywhere.
  • public static void main(String[] args): the entry point the JVM looks for. public so the JVM can call it, static so it can be called without creating an object, void because it returns nothing, and String[] args receives command-line arguments.
  • System.out.println(...): System is a class, out is its static field (a PrintStream), and println prints a line.
  • Statements end with ;, blocks use { }, and comments are // line or /* block */. Java is case-sensitive: Main and main are different.

Recent Java versions are adding simpler entry points for beginners (a preview feature allows an instance void main() without the class boilerplate), but the classic form above works everywhere and is what you will see in almost all existing code.

Primitive data types

Java has eight primitive types, which hold plain values and are not objects. Their sizes are fixed by the language, which is part of what makes programs portable (a C int can change size between platforms; a Java int never does):

public class Types {
    public static void main(String[] args) {
        System.out.println("byte    " + Byte.SIZE + " bits, " + Byte.MIN_VALUE + " to " + Byte.MAX_VALUE);
        System.out.println("short   " + Short.SIZE + " bits, " + Short.MIN_VALUE + " to " + Short.MAX_VALUE);
        System.out.println("int     " + Integer.SIZE + " bits, " + Integer.MIN_VALUE + " to " + Integer.MAX_VALUE);
        System.out.println("long    " + Long.SIZE + " bits, " + Long.MIN_VALUE + " to " + Long.MAX_VALUE);
        System.out.println("float   " + Float.SIZE + " bits, max " + Float.MAX_VALUE);
        System.out.println("double  " + Double.SIZE + " bits, max " + Double.MAX_VALUE);
        System.out.println("char    " + Character.SIZE + " bits (a UTF-16 code unit)");
        boolean flag = true;
        System.out.println("boolean " + flag);
        int big = Integer.MAX_VALUE;
        System.out.println("overflow: " + (big + 1));
        System.out.println("7 / 2 = " + 7 / 2 + ", 7 / 2.0 = " + 7 / 2.0 + ", 0.1 + 0.2 = " + (0.1 + 0.2));
    }
}
byte    8 bits, -128 to 127
short   16 bits, -32768 to 32767
int     32 bits, -2147483648 to 2147483647
long    64 bits, -9223372036854775808 to 9223372036854775807
float   32 bits, max 3.4028235E38
double  64 bits, max 1.7976931348623157E308
char    16 bits (a UTF-16 code unit)
boolean true
overflow: -2147483648
7 / 2 = 3, 7 / 2.0 = 3.5, 0.1 + 0.2 = 0.30000000000000004

Note three classic points: integer arithmetic overflows silently (adding 1 to the maximum int wraps to the minimum), dividing two integers gives an integer, and floating-point numbers are approximate (the same 0.1 + 0.2 result as in Python). For money, use BigDecimal, not double. Everything that is not a primitive, such as String, arrays and your own classes, is a reference type: the variable holds a reference to an object on the heap.

Java compared with C, C++ and Python

C C++ Java Python
Compiled to machine code machine code bytecode, then JIT bytecode, interpreted
Memory manual manual / RAII garbage collected garbage collected
Typing static static static dynamic
Pointers yes yes no (references only) no
Platform independence recompile per platform recompile same bytecode everywhere same source everywhere
Typical use OS, embedded games, systems enterprise, Android, big data scripting, data, AI, web

Java usually needs more code than Python for the same task, but its static types catch errors early, which is a big help in large teams and long-lived code.

Where Java is used

  • Enterprise back ends: banks, insurers, e-commerce and telecoms, usually with Spring or Jakarta EE.
  • Android: Android apps were first written in Java (Kotlin is now preferred, but both run on the same platform and interoperate).
  • Big data and search: Hadoop, Spark (partly), Kafka, Elasticsearch and Cassandra run on the JVM.
  • Web services and microservices.
  • Desktop and scientific tools.

Limits to know

  • Verbose syntax compared with newer languages, though recent versions (records, var, text blocks, pattern matching) have trimmed a lot of boilerplate.
  • Start-up time and memory: the JVM takes a moment to start and uses more memory than a small native program.
  • Not for low-level work: drivers and operating systems are written in C and C++.
  • The garbage collector can pause programs, though modern collectors keep pauses very short.

Common beginner mistakes

  • Naming the file differently from the public class (Hello.java must contain public class Hello).
  • Running java Hello.class instead of java Hello (give the class name, not the file name).
  • Having a runtime installed but no JDK, so javac is missing.
  • Forgetting the capital letter in String or System.
  • Missing static in main, or a wrong signature, so the JVM cannot find the entry point.
  • Comparing strings with == instead of .equals() (covered in part 1).

The Java series

  1. This post: what Java is, and the first program.
  2. Part 1: the basics: syntax, variables, operators, control flow, methods, arrays and your first classes.
  3. Part 2: object-oriented Java: inheritance, interfaces, collections, generics, exceptions and files.
  4. Part 3: modern and advanced Java: streams, concurrency, JDBC, modules and testing.

Practise what you learn by writing something small after each post. If you like to compare languages, the C++ guide and the Python fundamentals show the same ideas in different clothes.

Advertisement