说明
本文探讨的 JVM 参数和代码示例均适用于 JDK 8 版本。
用户类的位置
用户类是指由开发者或第三方定义的类,它们通过应用程序类加载器进行加载。
在 Java 程序中,可以通过设置 CLASSPATH
环境变量或 JVM 启动参数 -cp
和 -classpath
来指定类加载路径。这些配置的优先级从低到高,后设置的配置会覆盖先前的配置,默认路径为当前目录。
接下来,我们将验证默认值和优先级。
验证默认路径为当前路径
考虑一个名为 Temp.java 的类,它不位于任何包路径中:
public class Temp {
public static void main(String[] args) {
System.out.println("Executed!");
}
}
在没有设置 CLASSPATH
环境变量的情况下,将编译后的 Temp.class
文件放置在 E 盘,然后执行 java Temp
命令,程序能够正常运行。这说明类加载器是根据默认的类路径值找到该 Class 文件的,而这个默认值就是当前路径。
根据官方文档,Java 程序启动时会将 class path 的值放入 java.class.path
系统属性中。
修改代码,在程序运行时打印实际的 class path:
public class Temp {
public static void main(String[] args) {
System.out.println("Executed!");
System.out.println("The actual class path is :" + System.getProperty("java.class.path"));
}
}
执行结果表明,打印的结果是当前路径。
验证 CLASSPATH
环境变量的作用
在 Windows 系统中设置 CLASSPATH
环境变量,因为 Temp.class
文件位于 E 盘,所以环境变量也设置为 E 盘。
再次运行程序,结果表明通过配置的路径,类加载器能够找到 Temp.class
文件,并且打印的 class path 也是 E:。
验证 -cp
或 -classpath
参数的作用
移除 CLASSPATH
环境变量,通过执行 java 命令时指定 -cp
参数来设置 class path 路径。
程序执行的效果与通过 CLASSPATH
环境变量设置相同。
验证 -cp
或 -classpath
参数的优先级高于 CLASSPATH
环境变量
设置 CLASSPATH
环境变量为 D:,如果不带 -cp
参数执行,会提示找不到类,因为 D: 路径下没有 Temp.class
文件。
带上 -cp
参数后能够正常执行,说明 -cp
参数的配置生效了,其优先级高于 CLASSPATH
环境变量。
引导类的位置
sun.boot.class.path
系统属性的值
引导类包括构成 Java 平台的类,如 rt.jar 中的类,由引导类加载器(Bootstrap ClassLoader)加载。
如果直接在 Temp.class
文件所在的路径下执行 java Temp
命令,能够正常执行。那么 Temp
类的父类 Object
类位于 jre/lib
目录下的 rt.jar
包中,引导类加载器是如何找到并加载 Object 类的呢?
根据官方文档,引导类加载器加载的 class path 可以通过 sun.boot.class.path
系统属性获取。
public class Temp {
public static void main(String[] args) {
System.out.println("Executed!");
System.out.println("The actual class path is :" + System.getProperty("sun.boot.class.path"));
}
}
执行结果表明输出结果中包含 rt.jar 包的绝对路径。
sun.boot.class.path
系统属性赋值源码分析
以 Windows 平台为例,分析 HotSpot 虚拟机的源码实现,涉及三个文件:
hotspot\src\share\vm\runtime\arguments.cpp
hotspot\src\share\vm\runtime\os.cpp
hotspot\src\os\windows\vm\os_windows.cpp
源代码的调用链路如下:
arguments.cpp
负责处理 JVM 启动参数,初始化 _java_home
和 _sun_boot_class_path
系统属性。
然后调用 os_windows.cpp
的 init_system_properties_values()
方法,在该方法中会调用 os_windows.cpp
中的 jvm_path()
方法,尝试获取 jvm.dll
的绝对路径。
然后返回到 os_windows.cpp
的 init_system_properties_values()
方法,去除路径中的 jvm.dll
,server/client
,