Question
I installed Java 7 Update 17 on Mac OS X 10.7.5. I am starting JNI programming and need to find the location where Java is installed.
I expected to find a JDK directory, such as 1.7.0.jdk, inside:
/Library/Java/JavaVirtualMachines/
However, the directory is empty when I run:
ls /Library/Java/JavaVirtualMachines/
Where is Java installed on macOS, and how can I find the correct JDK path for JNI development?
Short Answer
On macOS, the reliable way to locate an installed JDK is /usr/libexec/java_home. A Java JRE installation may only provide a browser/runtime plugin and may not create a JDK directory or include the JNI header files required for native development. For JNI, install a full JDK and use its Contents/Home directory as JAVA_HOME.
Concept
Java installations on macOS can be confusing because Java may mean either a runtime environment or a development kit.
- A JRE (Java Runtime Environment) runs Java applications.
- A JDK (Java Development Kit) includes the JRE plus development tools such as
javac,javadoc, and the JNI C/C++ headers.
JNI development requires a JDK, because native code must include files such as:
include/jni.h
include/darwin/jni_md.h
A typical Oracle JDK 7 installation was stored as a versioned bundle under:
/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk
The actual Java home directory inside that bundle is:
/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home
Do not rely on a hard-coded version path. macOS provides /usr/libexec/java_home, a utility that finds installed JDKs and returns the correct Contents/Home path.
Mental Model
Think of a JRE as a car you can drive, while a JDK is a mechanic's workshop containing the car plus the tools needed to build and repair it.
Running a Java program only needs the car (the JRE). Building Java code or compiling JNI native libraries needs the workshop (the JDK).
The /Library/Java/JavaVirtualMachines directory is like a parking garage for installed JDK bundles. If it is empty, you may have installed only a runtime component rather than the full development kit.
Syntax and Examples
Use the macOS java_home tool to list JDKs that the system can detect:
/usr/libexec/java_home -V
The uppercase -V displays installed JVMs and their locations. For example, it may show:
Matching Java Virtual Machines (1):
1.7.0_17 (x86_64) "Oracle Corporation" - "Java SE 7" \
/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home
Get the path for the default JDK:
/usr/libexec/java_home
Get a specific Java major version:
/usr/libexec/java_home -v 1.7
Store the result in the JAVA_HOME environment variable for the current Terminal session:
export JAVA_HOME="$(/usr/libexec/java_home -v 1.7)"
echo "$JAVA_HOME"
Confirm that this is a JDK by checking for the Java compiler and JNI header:
ls "$JAVA_HOME/bin/javac"
ls
Step by Step Execution
Consider this Terminal session:
export JAVA_HOME="$(/usr/libexec/java_home -v 1.7)"
echo "$JAVA_HOME"
ls "$JAVA_HOME/include/jni.h"
/usr/libexec/java_home -v 1.7asks macOS to find an installed JDK compatible with Java 7.$(...)runs that command and substitutes its output into the surrounding command.export JAVA_HOME=...creates an environment variable namedJAVA_HOMEfor commands launched from this shell.echo "$JAVA_HOME"prints the selected JDK home, often a path ending inContents/Home.ls "$JAVA_HOME/include/jni.h"checks for the JNI header. If the file is listed, native code can includejni.h.
For example, a successful value could be:
/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home
If java_home reports that no matching JVM exists, install a full JDK rather than only a JRE or browser plugin.
Real World Use Cases
- Compiling a JNI library: A C or C++ build needs
jni.hand the macOS-specificjni_md.hheader. - Build tools: Maven, Gradle, and IDEs use
JAVA_HOMEto select the JDK used for compilation. - CI scripts: Build scripts often set
JAVA_HOMEexplicitly so every build uses the intended Java version. - Supporting multiple projects: One project may require Java 8 while another requires Java 17;
java_home -vselects the required JDK. - Troubleshooting: Comparing
java -version,javac -version, andJAVA_HOMEhelps identify a runtime/development-version mismatch.
Real Codebase Usage
Projects usually avoid embedding a fixed path such as jdk1.7.0_17.jdk in build scripts. Versioned directory names change whenever Java is updated.
A shell script can resolve the required JDK dynamically:
#!/usr/bin/env bash
set -euo pipefail
export JAVA_HOME="$(/usr/libexec/java_home -v 1.7)"
if [ ! -f "$JAVA_HOME/include/jni.h" ]; then
echo "A JDK with JNI headers is required." >&2
exit 1
fi
clang -I"$JAVA_HOME/include" \
-I"$JAVA_HOME/include/darwin" \
-dynamiclib native_example.c \
-o libnative_example.dylib
This pattern has two useful parts:
- It uses
java_homerather than a machine-specific installation path. - It validates that the needed JNI header exists before attempting compilation.
For a persistent interactive-shell setting, developers may add an appropriate JAVA_HOME export to their shell configuration file. A project-specific script or version manager is often safer when different projects require different Java versions.
Common Mistakes
Installing a JRE when JNI requires a JDK
A runtime can run Java programs but may not include JNI headers or javac.
# This can fail when only a runtime is installed.
ls /Library/Java/JavaVirtualMachines/*/Contents/Home/include/jni.h
Avoid it: install a full JDK, then verify jni.h through JAVA_HOME.
Using the java executable path as JAVA_HOME
This is not a Java home directory:
export JAVA_HOME="$(which java)" # Incorrect
which java usually returns an executable or a system launcher, not the JDK root.
Use this instead:
export JAVA_HOME="$(/usr/libexec/java_home)"
Hard-coding a specific update directory
JAVA_HOME=/Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home
Comparisons
| Item | Main purpose | Includes javac? | Includes jni.h? | Suitable for JNI compilation? |
|---|---|---|---|---|
| JRE | Run Java applications | No | Usually no | No |
| JDK | Develop, compile, and run Java | Yes | Yes | Yes |
java command | Launches a Java runtime | No | No | No |
JAVA_HOME | Points tools to a JDK home directory | Depends on its value | Depends on its value | Yes, when it points to a JDK |
Cheat Sheet
# List all JDKs macOS can find
/usr/libexec/java_home -V
# Print the default JDK home
/usr/libexec/java_home
# Print a Java 7 JDK home
/usr/libexec/java_home -v 1.7
# Set JAVA_HOME for the current shell
export JAVA_HOME="$(/usr/libexec/java_home -v 1.7)"
# Verify the compiler and JNI header
"$JAVA_HOME/bin/javac" -version
ls "$JAVA_HOME/include/jni.h"
# Typical JNI compilation flags on macOS
clang -I"$JAVA_HOME/include" -I"$JAVA_HOME/include/darwin" native.c
Key rules:
- JNI requires a JDK, not merely a JRE.
- Prefer
/usr/libexec/java_homeover hard-coded versioned paths. JAVA_HOMEshould point to a directory ending inContents/Home.- An empty
/Library/Java/JavaVirtualMachinesdirectory usually means a JDK is missing or not registered there.
FAQ
Where is a JDK usually installed on macOS?
A typical JDK is installed beneath /Library/Java/JavaVirtualMachines/. Its Java home is inside the bundle at .../Contents/Home.
How do I find Java's installation directory on macOS?
Run:
/usr/libexec/java_home
Use -V to list all detected JDK installations.
Why is /Library/Java/JavaVirtualMachines empty?
You may have installed a JRE, browser plugin, or another runtime component rather than a complete JDK. Install a JDK if you need javac or JNI headers.
What should JAVA_HOME be for JNI?
It should be the JDK home directory returned by /usr/libexec/java_home, such as a path ending in Contents/Home.
How can I check whether I have the JNI headers?
Run:
ls "$(/usr/libexec/java_home)/include/jni.h"
If the file does not exist, the selected installation is not a usable JDK for JNI.
Is a good way to find ?
Mini Project
Description
Create a small macOS shell script that finds a requested JDK, confirms that it contains the JNI header, and prints the compiler include flags needed for a JNI build. This reflects the validation commonly performed before native builds.
Goal
Produce a reusable script that selects a Java 7 JDK and reports whether it is ready for JNI development.
Requirements
- Use
/usr/libexec/java_hometo locate Java 7. - Store the returned path in
JAVA_HOME. - Exit with an error if no matching JDK is found.
- Exit with an error if
include/jni.his missing. - Print the macOS JNI include flags when the JDK is valid.
Keep learning
Related questions
Add External JAR Files to an IntelliJ IDEA Java Project
Learn how to add external JAR dependencies to an IntelliJ IDEA Java project using module libraries, and when to use Maven or Gradle instead.
Avoiding Java Code in JSP with JSP 2: EL and JSTL Explained
Learn how to avoid Java scriptlets in JSP 2 using Expression Language and JSTL, with examples, best practices, and common mistakes.
Call a Method After a Delay in Android Java
Learn how to run Java code after a delay in Android using Handler.postDelayed, manage the main thread, and cancel callbacks safely.