在 Linux 中安装 Oracle JDK 8 以及 JVM 的类加载机制(2)

  先来说说关于 Java 的闲话,大家都知道,运行 Java 程序需要一个启动器,比如 java 命令,大家也知道,在 Java 中一切都是类,只有属于类的方法,而没有单独的函数。这一点王垠大神有过批判。确实,Java 是一门纯面向对象的语言,太纯了,这个世界怎么可能所有的东西都是对象呢?本来就应该有一些东西应该存在于对象之外嘛,比如操作多个对象的纯函数,比如程序的入口点 main 函数。所以从语言的角度讲,Java 受到批判是理所当然的。但是, Java 的这种“纯”,简化了它的实现。因为 Java 中一切都是类,所以可以让 Java 代码编译后,每一个类生成一个 .class 文件,然后将 .class 文件放到相应的目录中,或者打包成 .jar 压缩包。程序运行的时候,用一个启动器将相应的 .class 文件加载,并执行其中的字节码即可。这种设计非常的简单、方便。而 C# 并不采用这种组织类和字节码的方式,却学 Java 让所有的函数都成为类的方法,我认为相反是不妥的。

  JVM 按如下顺序加载 .class 文件:

Bootstrap classes。这些类是 Java 平台的基础。其中包含大家都熟悉的 rt.jar,还包含其它一些类或 jar 包。

Extension classes。这些类扩展了 Java 平台,或者说,这些类利用了 Java 的扩展机制。这些类有两个要求:其一是必须打包成 jar,不能是单独的 .class 文件,并且这些 jar 包必须存放于 JDK/jre/lib/ext 目录下;其二是这些类不能引用 Bootstrap classes 和 Extension classes 之外的类。

User classes。也就是用户自定义类。我们自己写的程序已经我们从其它地方下载的第三方库都属于这个范畴。JVM 最后加载这些类,到哪里去找呢?这就需要用到 CLASSPATH 环境变量了,或者在程序启动的时候使用 -classpath 参数。

  在以上三个过程中,用户其实并不需要指定 Bootstrap classes 和 Extension classes 所在的目录,只需要指定 User classes 所在的目录就可以了。这是 JDK 8 和之前版本的区别。Bootstrap classes 和 Extension classes 所在的路径可以自动搜寻。前面的图片中我标出的 Java 系统配置中的 sun.boot.class.path 项就代表了 Bootstrap classes 所在的目录,默认为 JDK/jre/lib 中的 rt.jar 和其它一些 jar 文件。可以在启动程序的时候使用 -Xbootclasspath 选项更改这个路径。而 Extension classes 的路径就是 JDK/jre/lib/ext 目录,在前面的图片中我也标出来了。

  关于 User classes 的搜索路径,如果不指定的话,默认就是当前目录.,我前面图片中标出的就是默认值。如果重新指定 User classes 的搜索路径的话,就不会从当前目录进行搜索了,如果要从当前目录进行搜索,必须将当前目录明确地添加到 CLASSPATH 中。指定 User classes 的搜索路径有以下几种方式:

设置 CLASSPATH 环境变量;

程序启动时使用 -cp 或 -classpath 选项;

如果使用 java -jar 方式启动程序,则从 jar 包中的 manifest 文件中的 Class-Path 配置项中指定的路径搜索。

  搜索路径可以是目录,也可以是 jar 包,也可以是它们之间的任意组合,每一个项之间用:分割。另外,路径中还可以使用通配符*,但是该通配符只能匹配某一个目录下的所有 jar 包,而不能匹配 .class 文件,更加不能匹配子目录。

  那么问题来了,既然 CLASSPATH 中可以包含 jar 包,而 jar 包中又可以指定 Class-Path,而这个 Class-Path 中又可以指定其它的 jar 包,这样会造成无限循环吗?JVM 在搜索 jar 包的时候有什么规则吗?有的,如下三条:

jar包中指定的 Class-Path 会被当成 CLASSPATH 的组成部分,并且放在 jar 包中的其它 class 文件之前,而 class 文件的搜索是按照其路径出现在 CLASSPATH 中的顺序进行的,先找到先得。

如果之前扫面过的 jar 包又出现了,就不进行重复扫描;

如果一个 jar 包是作为 Java 的扩展安装的,也就是其在 JDK/jre/lib/ext 目录中,就忽略它的 Class-Path 配置项。

  关于 javac、javadoc 命令和 tools.jar 又有一些例外,这些例外的存在是因为 javac、javadoc 这些程序的运行对 .class 文件的双重需求决定的。作为 JDK 的工具, javac、javadoc 的运行需要 tools.jar 中的类的支持,另外,当 javac、javadoc 编译程序的时候,又需要解析源代码中对其它类的引用。它的基本规则如下:

运行 javac、javadoc 这些命令时,这些命令本身使用的 Bootstrap classes 、Extension classes 和 tools.jar 是不能改变的,它们只使用它们所在的 JDK 中的版本;

如果是 javac、javadoc 需要解析的其它的代码中用到了 tools.jar 中的类,则必须将 tools.jar 加入到 User classes 的搜索路径中才能起作用;如果要让它们解析的代码中引用不同版本的 Bootstrap classes 和 Extension classes,可以使用这两个命令的 -bootclasspath 和 -extdirs 选项指定。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/14952.html