macOS 如何定位 JAVA_HOME

多数的 Java 入门教程都是要求同时设置 JAVA_HOME 和 PATH(包含 $JAVA_HOME/bin) 两个环境变量,反正两个都有了就保险。其实一般情况下系统能在 PATH 中找到 java 程序时就知道 JAVA_HOME, 基本上只要配置 PATH 就行,而 JAVA_HOME 环境变量是可选的。但也有例外,比如 TOMCAT 就可能要求有 JAVA_HOME 环境变量。

在 macOS 下,JAVA_HOME 与 PATH 的关系又显得有点微妙了。一个新的 macOS 系统,它自带有 java 命令

$ which java
/usr/bin/java

你要直接执行它的话

$ java
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

所以它实际上只是执行 java 的辅助入口,没有实际的 JDK 或 JRE 是没用的。

用 PATH 覆盖 /usr/bin/java

当我们把 JDK 安装在非默认目录,如 /Users/yanbin/amazon-corretto-11.jdk,我们可以配置 PATH 来使用这个 JDK

export PATH=/Users/yanbin/amazon-correto-11.jdk/Contents/Home/bin:$PATH

然后可以执行

$ java -version
openjdk version "11.0.14.1" 2022-02-08 LTS

注意自己的路径要放在 $PATH 之前,否则仍然会执行 /usr/bin/java, 从而找不到 Java

macOS 定位 JAVA_HOME 有一个自己的命令 /usr/libexec/java_home, /usr/bin/java 就是仰赖于它来定位 JAVA_HOME 的。如果  JDK 在非默认目录中,/usr/libexec/java_home 是不知道的

$ /usr/libexec/java_home
The operation couldn’t be completed. Unable to locate a Java Runtime.
Please visit http://www.java.com for information on installing Java.

虽然依据 PATH 是可以执行 java 程序的。

/usr/libexec/java_home 定位

前面提到 macOS 的 JDK 安装默认目录,那就是 /Library/Java/JavaVirtualMachines, JDK 安装程序会安装 JDK 到该目录中,如

/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk

这时候我们不需要配置 PATH 环境变量(把 PATH 环境变量恢复成默认,或打开一个新的终端),再执行 /usr/libexec/java_home 就能找到该默认位置下的 JDK11

$ /usr/libexec/java_home
/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home

执行 java

$ java -version
openjdk version "11.0.14.1" 2022-02-08 LTS

不光是执行 JDK 安装程序的方式,就是我们直接解压 JDK 到目录也行。例如我们解压 JDK 8 到该目录中

$ ls /Library/Java/JavaVirtualMachines
amazon-corretto-11.jdk amazon-corretto-8.jdk

看看此时 macOS 会选择哪个 JDK

列出来两个 JDK, 但选择了 JDK 11

再来一个 JDk

$ ls /Library/Java/JavaVirtualMachines
amazon-corretto-11.jdk amazon-corretto-17.jdk amazon-corretto-8.jdk

看来在 /Library/Java/JavaVirtualMachines 中有多个 JDK 版本时,/usr/libexec/java_home 会选择最高版本。

用 JAVA_HOME 选择 JDK 版本

那么如何让 /usr/bin/java 选择自己想要的 JDK 版本呢,设定 JAVA_HOME, 而不是让 /usr/libexec/java_home 自主选择最高的版本。

比如我们在 /Library/Java/JavaVirtualMachines 中有三个 JDK 版本时,想用 JDK 8

export JAVA_HOME=/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
$ java -version
openjdk version "1.8.0_322"

/usr/libexec/java_home 的高级用法

命令帮助

除了 /usr/libexec/java_home -V 可列出 /Library/Java/JavaVirtualMachines 中的所有 JDK 版本及路径,以及首选的 JDK 外,用 /usr/libexec/java_home -X 能以 plist XML 格式展示所有 JDK

$ /usr/libexec/java_home -X

还能用 /usr/libexec/java_home -v xxx 智能的显示所对应版本的 JAVA_HOME

$ /usr/libexec/java_home -v 1.8
/Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
$ /usr/libexec/java_home -v 11
/Library/Java/JavaVirtualMachines/amazon-corretto-11.jdk/Contents/Home
$ /usr/libexec/java_home -v 8
/Library/Java/JavaVirtualMachines/amazon-corretto-18.jdk/Contents/Home

结合 /usr/libexec/java_home -v xxx 选项,我们就可以用一个脚本来切换 JAVA_HOME,核心就是

export JAVA_HOME=$(/usr/libexec/java_home -v $1)

根据所使用 shell 的不同,比如我们可以在 ~/.bashrc 或 ~/.zshrc 文件中定义一个函数

然后执行 switch_java 来切换

$ switch_java 11
$ switch_java 1.8
$ switch_java 17

Demo

$  java -version
openjdk version "11.0.14.1" 2022-02-08 LTS
OpenJDK Runtime Environment Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS)
OpenJDK 64-Bit Server VM Corretto-11.0.14.10.1 (build 11.0.14.1+10-LTS, mixed mode)
$  switch_java 1.8
switch JAVA_HOME to /Library/Java/JavaVirtualMachines/amazon-corretto-8.jdk/Contents/Home
$  java -version
openjdk version "1.8.0_322"
OpenJDK Runtime Environment Corretto-8.322.06.1 (build 1.8.0_322-b06)
OpenJDK 64-Bit Server VM Corretto-8.322.06.1 (build 25.322-b06, mixed mode)

如果把 export JAVA_HOME=$(/usr/libexec/java_home -v $1) 定义在别的脚本文件中要用 source switch_java.sh 1.8 来切换

最后注意在用 /usr/libexec/java_home 定位 JAVA_HOME 时不需要为 JAVA 定制 PATH,要以 /usr/bin/java 作为入口。

javac 也一样

$ which javac
/usr/bin/javac

更多 /usr/bin 下的 java 命令

如果有 JDK 中无法被 /usr/bin 下 j* 覆盖的命令,就要从 $JAVA_HOME/bin 中找,所以必要时在修改 JAVA_HOME 环境变量后,也应更新 PATH 环境变量。

关于 Linux 下如何找到 JAVA_HOME, 有两个命令

链接:

  1. How to Find JAVA_HOME

类别: Java/JEE. 标签: , , . 阅读(72). 订阅评论. TrackBack.
guest
0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x