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
- 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). - 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.
- 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.publicmeans visible everywhere.public static void main(String[] args): the entry point the JVM looks for.publicso the JVM can call it,staticso it can be called without creating an object,voidbecause it returns nothing, andString[] argsreceives command-line arguments.System.out.println(...):Systemis a class,outis its static field (aPrintStream), andprintlnprints a line.- Statements end with
;, blocks use{ }, and comments are// lineor/* block */. Java is case-sensitive:Mainandmainare 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.javamust containpublic class Hello). - Running
java Hello.classinstead ofjava Hello(give the class name, not the file name). - Having a runtime installed but no JDK, so
javacis missing. - Forgetting the capital letter in
StringorSystem. - Missing
staticinmain, 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
- This post: what Java is, and the first program.
- Part 1: the basics: syntax, variables, operators, control flow, methods, arrays and your first classes.
- Part 2: object-oriented Java: inheritance, interfaces, collections, generics, exceptions and files.
- 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.