歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux基礎 >> Linux教程 >> 在 Linux 中安裝 Oracle JDK 8 以及 JVM 的類加載機制

在 Linux 中安裝 Oracle JDK 8 以及 JVM 的類加載機制

日期:2017/2/28 13:48:31   编辑:Linux教程

閱讀目錄

  • 參考資料
  • 前言
  • 下載和安裝Oracle JDK
  • 類文件如何被發現並加載
  • CLASSPATH和Package的關系
  • 總結

參考資料

  該文中的內容來源於 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 VisualVM 和商業化的 Java Mission Control 等等。最後,就是商標不一樣了,請記住,Java 現在是 Oracle 的注冊商標哦。至於授權協議的不同,我們普通用戶不需要關心,既然 Oracle 提供免費下載,那我們只管用就是了。

  測試Linux版本:Fedora 21

  另外,在 Java SE 8 文檔中,還有這樣一副圖片,完整地展示了 Java SE 的組成。在官網中的該圖片的每一個小方格都是一個超鏈接,如果想學習哪一塊的知識,點擊相應的小方塊就可以了。我這裡只是一個截圖,沒有導航功能。把圖片放到這裡,就是讓自己對 Java 的核心技術有一個總攬。如下圖:

下載和安裝Oracle JDK

  要下載 Oracle JDK,肯定要去 Oracle官網 ,在官網裡面找到 Java 的下載頁面是沒有什麼難度的,我就不多說了。我選擇的版本是 JDK 8 For Linux 的 64 位版本。同時,我沒有選擇 rpm 包,而是選擇了 .tar.gz 這個壓縮包,如下圖:

  將壓縮包下載下來後,放到我自己的主目錄,解壓後就可以使用。這完全是我自己的私有版本,不會與系統中安裝的其它 Java 版本發生沖突。缺點就是當我要調用 javajavac 這樣的命令的時候,我必須指定完整的路徑。解壓的命令為 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 的時候就不用每次都輸入完整路徑了。另外,如果想更改全局的環境變量,可以修改 /etc/environment 配置文件。其實在從 Oracle 官網下載 JDK 的時候,完全可以選擇 rpm 包的版本,安裝後,可以使用 sudo update-alternative --config java 更改默認的 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 文件:

  1. Bootstrap classes。這些類是 Java 平台的基礎。其中包含大家都熟悉的 rt.jar,還包含其它一些類或 jar 包。
  2. Extension classes。這些類擴展了 Java 平台,或者說,這些類利用了 Java 的擴展機制。這些類有兩個要求:其一是必須打包成 jar,不能是單獨的 .class 文件,並且這些 jar 包必須存放於 JDK/jre/lib/ext 目錄下;其二是這些類不能引用 Bootstrap classes 和 Extension classes 之外的類。
  3. 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 的搜索路徑有以下幾種方式:

  1. 設置 CLASSPATH 環境變量;
  2. 程序啟動時使用 -cp 或 -classpath 選項;
  3. 如果使用 java -jar 方式啟動程序,則從 jar 包中的 manifest 文件中的 Class-Path 配置項中指定的路徑搜索。

  搜索路徑可以是目錄,也可以是 jar 包,也可以是它們之間的任意組合,每一個項之間用:分割。另外,路徑中還可以使用通配符*,但是該通配符只能匹配某一個目錄下的所有 jar 包,而不能匹配 .class 文件,更加不能匹配子目錄。

  那麼問題來了,既然 CLASSPATH 中可以包含 jar 包,而 jar 包中又可以指定 Class-Path,而這個 Class-Path 中又可以指定其它的 jar 包,這樣會造成無限循環嗎?JVM 在搜索 jar 包的時候有什麼規則嗎?有的,如下三條:

  1. jar包中指定的 Class-Path 會被當成 CLASSPATH 的組成部分,並且放在 jar 包中的其它 class 文件之前,而 class 文件的搜索是按照其路徑出現在 CLASSPATH 中的順序進行的,先找到先得。
  2. 如果之前掃面過的 jar 包又出現了,就不進行重復掃描;
  3. 如果一個 jar 包是作為 Java 的擴展安裝的,也就是其在 JDK/jre/lib/ext 目錄中,就忽略它的 Class-Path 配置項。

  關於 javacjavadoc 命令和 tools.jar 又有一些例外,這些例外的存在是因為 javacjavadoc 這些程序的運行對 .class 文件的雙重需求決定的。作為 JDK 的工具, javacjavadoc 的運行需要 tools.jar 中的類的支持,另外,當 javacjavadoc 編譯程序的時候,又需要解析源代碼中對其它類的引用。它的基本規則如下:

  1. 運行 javacjavadoc 這些命令時,這些命令本身使用的 Bootstrap classes 、Extension classes 和 tools.jar 是不能改變的,它們只使用它們所在的 JDK 中的版本;
  2. 如果是 javacjavadoc 需要解析的其它的代碼中用到了 tools.jar 中的類,則必須將 tools.jar 加入到 User classes 的搜索路徑中才能起作用;如果要讓它們解析的代碼中引用不同版本的 Bootstrap classes 和 Extension classes,可以使用這兩個命令的 -bootclasspath 和 -extdirs 選項指定。

  最後,類的加載還受 Class Loader 和 安全策略(Security Policies)的影響。在 Java 中,我們���以使用不同的 Class Loader,也可以編寫自己的 Class Loader,但是大部分時候,我們都是使用的內置的 Class Loader。在 Java 中可以啟用不同的安全策略,我們信任的類就允許它加載,不信任的就不允許。如果沒有開啟安全策略,則所有的類都認為是被信任的。但是即使開啟了安全策略,也只會影響到 Extension classes 和 User classes,對 Bootstrap classes 是沒有影響的。

CLASSPATH和Package的關系

  在 Java 中還有一個讓人頭疼的地方,就是 .class 文件的存放位置和 package 之間的關系。在 Java 語言中,為了不發生命名沖突,特意引入了 package 機制,將 Java 中的類劃分到不同的 package 之中。在前面我展示的 HelloWorld.java 中,我將它的 package 設置為 com.xkland.java_8_study,然後編譯這個程序的時候,我特意使用了 javac -d . 選項,設置將當前目錄 . 作為編譯後的目標位置。編譯完成後,我還特意使用 tree 命令查看了一下目錄的結構。

  從結果中可以看出,HelloWorld.class 存放的位置為 ./com/xkland/java_8_study/HelloWorld.class。這個目錄層次和 package 的命名是完全一致的。而且必須一致,否則將會找不到 .class 文件,也無法運行程序。所以,如果你的 package 的命名是 a.b.c.d 這樣的,則只能組織成 a/b/c/d/xx.class 這樣的目錄樹,並且從 a 目錄的上一級目錄開始搜索這個 class 才找得到,也就是說,必須將 a 目錄的上一級目錄加入 CLASSPATH。對於源代碼沒有這個限制,但是使用同樣的方式組織源代碼是一個好的做法。如果源代碼目錄是扁平的,就像我前面的例子一樣,則調用 javac 的時候一定要指定 -d 參數,它會自動生成 .class 文件的目錄結構。

總結

  沒什麼好總結的。就是看了 Oracle Java SE 8 官方文檔後的一點記錄。 How classes are found? 還是值得偶爾復習一下的。

Ubuntu 14.04安裝JDK1.8.0_25與配置環境變量 http://www.linuxidc.com/Linux/2015-01/112030.htm

CentOS 搭建JDK環境 http://www.linuxidc.com/Linux/2015-06/118879.htm

Ubuntu 14.04安裝JDK1.8.0_25與配置環境變量 http://www.linuxidc.com/Linux/2015-01/112030.htm

Ubuntu 14.04 LTS安裝Oracle JDK 1.8 http://www.linuxidc.com/Linux/2014-11/109216.htm

CentOS6.3安裝JDK和環境配置 http://www.linuxidc.com/Linux/2012-09/70780.htm

Ubuntu 14.04 安裝 JDK8 http://www.linuxidc.com/Linux/2014-09/106218.htm

Ubuntu下安裝JDK圖文解析 http://www.linuxidc.com/Linux/2014-09/107291.htm

Copyright © Linux教程網 All Rights Reserved