Java JDK
The JDK (Java Development Kit) is the complete toolkit for building Java software. It contains the compiler, the runtime, the standard class library, and a set of command-line tools for packaging, documenting, inspecting, and troubleshooting Java programs. Every Java IDE and build tool works by calling the tools inside a JDK.
What Is Inside a JDK
A JDK installation is an ordinary directory. Its layout is the same for every vendor:
jdk-25/
├── bin/ executables: java, javac, jshell, jar, javadoc, jlink, jcmd, ...
├── conf/ configuration: security policy, logging, network properties
├── include/ C header files for writing native code (JNI)
├── jmods/ the platform modules in a form jlink can package
├── legal/ licence files for each component
├── lib/ the JVM itself, the class library (modules file), and supporting files
└── release a text file describing the version and included modules
The release file is a quick way to identify an unknown installation:
cat $JAVA_HOME/release
JAVA_VERSION="25.0.1"
IMPLEMENTOR="Eclipse Adoptium"
...
The standard class library
The thousands of classes you use without writing them (String, ArrayList, HashMap, Files, HttpClient, LocalDate) are part of the JDK. Since Java 9 they are organized into modules such as java.base (core language classes), java.sql (JDBC), java.net.http (HTTP client), and java.desktop (Swing and AWT). You can list them:
java --list-modules
java.base@25.0.1
java.compiler@25.0.1
java.datatransfer@25.0.1
java.desktop@25.0.1
...
Every program automatically has access to java.base. Code on the classpath (the normal case for beginners) can use all the standard Java SE modules without any configuration.
The Core Tools
| Tool | Purpose |
|---|---|
javac | Compiles .java source files into .class bytecode |
java | Starts a JVM and runs a program (a class, a JAR, or a single source file) |
jshell | Interactive console: evaluate Java statements and expressions immediately |
jar | Packages compiled classes and resources into a .jar archive |
javadoc | Generates HTML API documentation from /** ... */ comments |
javap | Disassembles .class files to show their methods and bytecode |
jdeps | Analyses which packages and modules a JAR depends on |
jlink | Builds a minimal custom runtime image containing only the modules an app needs |
jpackage | Creates native installers (.msi, .pkg, .deb, .rpm) for an application |
jcmd | Sends diagnostic commands to a running JVM (thread dumps, heap info, GC) |
jstack, jmap, jstat | Inspect threads, memory, and GC statistics of a running JVM |
jfr | Reads recordings from Java Flight Recorder, the built-in profiler |
keytool | Manages keystores of certificates and keys for TLS |
Beginners use javac, java, and jshell constantly. The others become important when packaging, deploying, and troubleshooting applications, and each is covered in later sections.
The Development Cycle Using JDK Tools
Hello.java --javac--> Hello.class --jar--> app.jar --java--> running program
source bytecode packaged
A minimal walk-through:
// Hello.java
public class Hello {
public static void main(String[] args) {
System.out.println("Built with the JDK");
}
}
javac Hello.java # produces Hello.class
java Hello # runs it
jar --create --file app.jar --main-class Hello Hello.class # packages it
java -jar app.jar # runs the packaged app
Output (from both java commands):
Built with the JDK
javacchecks the code and producesHello.class.java Helloruns the class by name (no.classextension).jar --createbuilds a ZIP-format archive.--main-class Hellorecords the entry point in the JAR's manifest, sojava -jar app.jarknows which class to start.
Inspecting a class with javap
javap Hello
Compiled from "Hello.java"
public class Hello {
public Hello();
public static void main(java.lang.String[]);
}
javap reads a compiled class and lists its members. Notice public Hello();: the compiler added a default constructor that was never written in the source. Adding -c shows the bytecode instructions inside each method, which is useful for understanding what the compiler actually generates.
JDK Versus JRE Versus JVM
| Contains | Used for | |
|---|---|---|
| JVM | The execution engine: class loading, bytecode verification, interpreter, JIT compiler, garbage collector | Running bytecode |
| JRE | JVM + standard class library | Running Java applications |
| JDK | JRE + development tools (javac, jar, jshell, javadoc, ...) | Writing, building, and running Java applications |
Each layer contains the one beneath it. The JRE and JVM have their own lessons. Since Java 11, vendors distribute the JDK as the standard download; a minimal runtime for deployment is produced with jlink instead.
JDK Versions
A JDK's version determines which language features the compiler accepts and which APIs the library provides. The --release option compiles code for an older target version using a newer JDK:
javac --release 17 Hello.java
The compiler then rejects language features and API calls that do not exist in Java 17, and produces class files that a Java 17 JVM can run. This is how libraries built with a modern JDK stay compatible with users on older versions.
To see what a JDK supports:
javac --help # options, including --release
java -version # runtime version
javac -version # compiler version
Creating a Custom Runtime with jlink
A full JDK is several hundred megabytes. A deployed application needs only the modules it actually uses. jdeps finds them, and jlink packages a runtime containing only those:
jdeps --print-module-deps app.jar
# java.base,java.net.http
jlink --add-modules java.base,java.net.http \
--output myruntime \
--strip-debug --no-header-files --no-man-pages
./myruntime/bin/java -jar app.jar
myruntime is a self-contained runtime, often tens of megabytes rather than hundreds, that can be shipped with the application or placed in a small Docker image. This is the modern replacement for installing a separate JRE on every machine.
JShell: Experimenting Without Files
JShell runs Java code immediately, without a class, a main method, or compilation:
jshell> var names = List.of("Ada", "Linus", "Grace")
names ==> [Ada, Linus, Grace]
jshell> names.stream().map(String::toUpperCase).toList()
$2 ==> [ADA, LINUS, GRACE]
jshell> Math.sqrt(2)
$3 ==> 1.4142135623730951
It is the fastest way to check how an API behaves or test a small expression. JShell has its own lesson later in this section.
Diagnosing a Running Program
The monitoring tools work on any running Java process. jcmd with no arguments lists JVMs on the machine:
jcmd
48213 Hello
48290 jdk.jcmd/sun.tools.jcmd.JCmd
Then send commands to one of them by process ID:
jcmd 48213 VM.version # version of that JVM
jcmd 48213 Thread.print # stack trace of every thread
jcmd 48213 GC.heap_info # heap usage
A thread dump is the first thing to collect when an application hangs: it shows exactly where each thread is waiting. These tools ship with every JDK, which is one reason production servers often run a full JDK rather than a stripped runtime. They are covered further in the JVM Monitoring lesson.