该文中的内容来源于 Oracle 的官方文档 Java SE Tools Reference 。Oracle 在 Java 方面的文档是非常完善的。对 Java 8 感兴趣的朋友,可以直接找到这个总入口 Java SE 8 Documentation ,想阅读什么就点什么。本博客不定期从 Oracle 官网搬砖。
前言在 Linux 中使用 Java,我一般都是直接使用 Linux 发行版自带的软件包,一个命令即可搞定 JDK 的安装。但是 Linux 发行版中自带的 JDK 往往是 OpenJDK,虽说不影响使用,但是如果要按照 Oracle 的文档进行学习,还是安装一个 Oracle JDK 比较好。OpenJDK 和 Oracle JDK 颇有渊源,其内容大部分都是一样的,除了少数 Oracle JDK 中涉及到专利技术或授权因素的部分代码。另外,Oracle JDK 自带的工具要更多一点,如商业化的 Java Mission Control。最后,就是商标不一样了,请记住,Java 现在是 Oracle 的注册商标哦。至于授权协议的不同,我们普通用户不需要关心,既然 Oracle 提供免费下载,那我们只管用就是了。
另外,在 Java SE 8 文档中,还有这样一副图片,完整地展示了 Java SE 的组成。在官网中的该图片的每一个小方格都是一个超链接,如果想学习哪一块的知识,点击相应的小方块就可以了。我这里只是一个截图,没有导航功能。把图片放到这里,就是让自己对 Java 的核心技术有一个总揽。如下图:
要下载 Oracle JDK,肯定要去 Oracle官网 ,在官网里面找到 Java 的下载页面是没有什么难度的,我就不多说了。我选择的版本是 JDK 8 For Linux 的 64 位版本。同时,我没有选择 rpm 包,而是选择了 .tar.gz 这个压缩包,如下图:
将压缩包下载下来后,放到我自己的主目录,解压后就可以使用。这完全是我自己的私有版本,不会与系统中安装的其它 Java 版本发生冲突。缺点就是当我要调用 java、javac 这样的命令的时候,我必须指定完整的路径。解压的命令为 tar zxf jdk1.8.0u45-linux-x64.tar.gz。
熟悉 Java 的朋友肯定知道,以前安装 JDK 的时候,必须设置 PATH 和 CLASSPATH 两个环境变量。但是在 JDK 8 中,这都不是必须的。不设置 PATH 环境变量是因为在我的系统中存在 OpenJDK,即使将 ~/jdk1.8.0_45/bin 加入到 PATH,调用 java 命令的时候使用的依然是 OpenJDK。所以使用 Oracle JDK 的时候,我就直接输完整路径好了。不设置 CLASSPATH 的原因是 Java SE 8 可以自动探测 Class 所在的路径。当然,设置 CLASSPATH 环境变量也是可以的,只是没有那个必要了。如下图:
(截完图后我又想到,其实要想覆盖 OpenJDK 的 java 命令也是可以的,只要这样设置环境变量 export PATH=~/jdk1.8.0_45/bin:$PATH,而不是 export PATH=$PATH:~/jdk1.8.0_45/bin 就可以了。使用 Oracle JDK 的时候就不用每次都输入完整路径了。)
然后,写个 HelloWorld 程序测试一下。这个程序实在是太简单了,根本没有必要动用 Eclipse 这样庞大的 IDE,使用 Vim 足以。如下图:
写这个测试程序就是为了证明 Oracle JDK 8 可以运行,特别是为了证明 JDK 8 不用设置 CLASSPATH 环境变量也可以运行。这个程序除了输出“Hello, world!”以外,还输出 Java 运行时默认的系统配置。如下图:
在这些默认的系统配置中,有几个比较重要的值,我特意用红色的框框将其标记出来了。Java 运行时就是从这些路径中加载 class 的。如下图:
下面来看 Java 运行时是如何搜寻并加载 class 的。在以下文字中,我均使用 JDK 代替 ~/jdk1.8.0_45 目录,表示 Oracle JDK 8 的安装路径。
类文件如何被发现并加载先来说说关于 Java 的闲话,大家都知道,运行 Java 程序需要一个启动器,比如 java 命令,大家也知道,在 Java 中一切都是类,只有属于类的方法,而没有单独的函数。这一点王垠大神有过批判。确实,Java 是一门纯面向对象的语言,太纯了,这个世界怎么可能所有的东西都是对象呢?本来就应该有一些东西应该存在于对象之外嘛,比如操作多个对象的纯函数,比如程序的入口点 main 函数。所以从语言的角度讲,Java 受到批判是理所当然的。但是, Java 的这种“纯”,简化了它的实现。因为 Java 中一切都是类,所以可以让 Java 代码编译后,每一个类生成一个 .class 文件,然后将 .class 文件放到相应的目录中,或者打包成 .jar 压缩包。程序运行的时候,用一个启动器将相应的 .class 文件加载,并执行其中的字节码即可。这种设计非常的简单、方便。而 C# 并不采用这种组织类和字节码的方式,却学 Java 让所有的函数都成为类的方法,我认为相反是不妥的。
JVM 按如下顺序加载 .class 文件:
Bootstrap classes。这些类是 Java 平台的基础。其中包含大家都熟悉的 rt.jar,还包含其它一些类或 jar 包。