Java虛擬機基礎教程_第1頁
Java虛擬機基礎教程_第2頁
Java虛擬機基礎教程_第3頁
Java虛擬機基礎教程_第4頁
Java虛擬機基礎教程_第5頁
已閱讀5頁,還剩284頁未讀 繼續免費閱讀

付費下載

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

\hJava虛擬機基礎教程目錄\h第1章Java虛擬機\h1.1JVM實現\h1.2為何要在JVM上開發\h1.2.1JVM適應市場的變化\h1.2.2Java類庫\h1.2.3生態系統\h1.3常見的用途\h1.3.1Web應用程序\h1.3.2大數據\h1.3.3IoT\h1.4JVM概念\h1.4.1虛擬機\h1.4.2JIT編譯器\h1.4.3基本數據類型\h1.4.4類\h1.4.5引用類型\h1.4.6垃圾收集器\h1.4.7向后兼容\h1.4.8構建工具\h1.5Java版本\h1.5.1JavaSE\h1.5.2JavaEE\h1.5.3JavaME\h1.6其他JVM語言\h1.6.1為何選擇其他語言\h1.6.2在同一個項目中使用多種JVM語言\h1.6.3使用另一種語言編寫單元測試\h1.7小結\h第2章Java虛擬機開發\h2.1JDK\h2.1.1安裝JDK\h2.1.2探索JDK\h2.1.3JRE\h2.2使用包組織類\h2.2.1包是什么\h2.2.2選擇包名\h2.2.3包名舉例\h2.2.4全限定類名\h2.3Java類庫\h2.3.1Java類庫的組織結構\h2.3.2包概述\h2.3.3java.lang包中的重要類\h2.3.4集合API——java.util.ArrayList和java.util.HashMap\h2.4從命令行運行JVM應用程序\h2.4.1至少有一個類包含靜態方法main()\h2.4.2存儲類文件的目錄結構\h2.4.3為JVM實例設置ClassPath\h2.4.4將類文件放在JAR歸檔文件中\h2.4.5使用命令java運行程序\h2.4.6在JVM中運行的示例項目\h2.5EclipseIDE\h2.5.1下載EclipseIDE\h2.5.2安裝EclipseIDE\h2.6小結\h第3章Java\h3.1Java中的面向對象編程功能\h3.1.1定義類\h3.1.2類訪問限定符\h3.1.3類限定符final——鎖定類\h3.1.4定義包\h3.1.5導入類\h3.1.6添加類成員——變量和方法\h3.1.7限定符\h3.1.8構造函數和終結方法\h3.1.9向上轉換和向下轉換\h3.2編寫Java代碼\h3.2.1運算符\h3.2.2條件檢查\h3.2.3POJO\h3.2.4數組\h3.2.5泛型和集合\h3.2.6循環\h3.2.7異常\h3.2.8線程\h3.2.9lambda\h3.3編程風格指南\h3.4小測驗\h3.5小結\h第4章Java編程\h4.1配置EclipseIDE\h4.2使用Java創建Web服務\h4.2.1在EclipseIDE中新建Gradle項目\h4.2.2修改Gradle構建文件\h4.2.3構建項目\h4.2.4編寫后端類\h4.3小結\h第5章Scala\h5.1安裝Scala\h5.2Scala的REPLshell\h5.3函數式編程和命令式編程\h5.4Scala語法和規則\h5.4.1靜態類型語言\h5.4.2可修改的變量和不可修改的變量\h5.4.3常用的Scala類型\h5.5Scala的OOP功能\h5.5.1定義包和子包\h5.5.2導入成員\h5.5.3定義類\h5.5.4實例變量和實例方法\h5.5.5構造函數\h5.5.6擴展類\h5.5.7重載方法\h5.5.8抽象類\h5.5.9特質\h5.5.10單例對象\h5.5.11運算符重載\h5.5.12Case類\h5.6Scala標準庫\h5.6.1泛型\h5.6.2集合\h5.6.3XML處理\h5.7Scala的函數式編程功能\h5.7.1使用函數遍歷集合\h5.7.2映射-過濾-歸約設計模式\h5.7.3柯里化\h5.8小測驗\h5.9小結\h第6章Scala編程\h6.1ScalaIDEforEclipse插件\h6.1.1安裝ScalaIDEforEclipse\h6.1.2切換到ScalaIDE透視圖\h6.2SBT\h6.2.1安裝SBT\h6.2.2創建基于SBT的EclipseIDE項目\h6.2.3Scala編譯器(scalac)\h6.3創建Akka項目\h6.3.1在SBT構建文件中添加Akka依賴項\h6.3.2更新ScalaIDE項目\h6.3.3Akka概念\h6.3.4創建第一個AkkaActor——QuotesHandlerActor\h6.3.5創建消息\h6.3.6編寫基于ScalaTest的單元測試\h6.3.7實現消息處理程序\h6.3.8創建QuotePrinterActor\h6.3.9主應用程序\h6.4小結\h第7章Clojure\h7.1安裝Clojure\h創建啟動腳本\h7.2Clojure的交互式shell(REPL)\h7.3Clojure語言\h7.3.1語法\h7.3.2表達式\h7.3.3定義變量\h7.3.4定義函數\h7.3.5數據結構\h7.4使用Java類\h使用deftype和defrecord創建簡單的Java類\h7.5使用代理管理狀態\h代理示例\h7.6風格指南\h7.7小測驗\h7.8小結\h第8章Clojure編程\h8.1EclipseIDE插件Counterclockwise\h8.1.1安裝插件Counterclockwise\h8.1.2切換到Java透視圖\h8.2構建工具Leiningen\h安裝Leiningen\h8.3創建可執行的Clojure程序\h8.3.1在不使用Leiningen的情況下將代碼編譯成類文件\h8.3.2使用Leiningen編譯項目\h8.4新建Counterclockwise項目\h8.4.1EclipseIDE中的ClojureREPL\h8.4.2更新項目的Clojure版本\h8.4.3添加依賴\h8.5以測試驅動開發的方式探索monad\h8.6Web框架Luminus\h8.6.1創建Luminus項目\h8.6.2將項目導入Counterclockwise\h8.6.3探索Luminus項目\h8.6.4在Web應用程序中添加頁面\h8.7小結\h第9章Kotlin\h9.1安裝Kotlin\h啟動腳本\h9.2Kotlin的REPL交互式shell\h9.3Kotlin語言基礎\h9.3.1定義局部變量\h9.3.2定義函數\h9.3.3Kotlin類型\h9.3.4循環\h9.4Kotlin的OOP功能\h9.4.1定義包\h9.4.2導入成員\h9.4.3定義類和構造函數\h9.4.4給類添加成員\h9.4.5繼承\h9.4.6接口\h9.4.7可見性限定符\h9.4.8單例對象和伴生對象\h9.4.9數據類\h9.4.10lambda和內聯函數\h9.5Kotlin過程性編程\h9.6風格指南\h9.7小測驗\h9.8小結\h第10章Kotlin編程\h10.1EclipseIDEKotlin插件\h10.1.1安裝EclipseIDEKotlin插件\h10.1.2切換到Kotlin透視圖\h10.2ApacheMaven\h10.2.1安裝ApacheMaven\h10.2.2下載預制的Kotlin基本套件\h10.2.3在EclipseIDE中導入項目\h10.2.4探索構建文件pom.xml\h10.2.5在Eclipse中更新構建文件\h10.3創建JavaFX桌面GUI應用程序\h10.3.1定制項目\h10.3.2創建可運行的應用程序\h10.3.3編寫擴展函數\h10.3.4布局窗格\h10.3.5實現基于BorderPane的布局\h10.3.6實現動畫\h10.3.7調試程序\h10.4小結\h第11章Groovy\h11.1安裝Groovy\hGroovyConsole和GroovyShell\h11.2Groovy語言\hGroovy面向對象編程\h11.3Groovy開發包(GDK)\h11.3.1Groovy字符串(GString)\h11.3.2集合\h11.4動態和靜態編程\h11.4.1元編程\h11.4.2Groovy靜態編程\h11.5小測驗\h11.6小結\h第12章Groovy編程\h12.1安裝GroovyEclipse插件\h切換到Java透視圖\h12.2ApacheIvy和IvyDE\h安裝用于EclipseIDE的ApacheIvyDE插件\h12.3創建并配置項目\h12.3.1新建GroovyEclipse項目\h12.3.2創建供Ivy使用的ivy.xml文件\h12.4JavaDatabaseConnectivity(JDBC)\h12.4.1H2數據庫\h12.4.2創建內存數據庫\h12.5使用MarkupBuilder生成XML\h根據SQL查詢結果生成XML\h12.6微服務平臺Vert.x\h12.6.1在文件ivy.xml中添加Vert.x依賴\h12.6.2創建Web服務\h12.7小結\h附錄A其他JVM語言\hA.1OracleNashorn\hA.1.1在基于JVM的項目中嵌入Nashorn\hA.1.2運行Nashorn\hA.2Jython(Python)\hA.2.1CPython和Jython的不同之處\hA.2.2運行Jython\hA.3JRuby(Ruby)\hA.3.1RubyonRails和JRuby\hA.3.2運行JRuby\hA.4Frege(Haskell)\hA.4.1在Frege中調用Java代碼\hA.4.2運行Frege\hA.5Ceylon\hA.5.1Ceylon的模塊系統\hA.5.2運行Ceylon\hA.6小結\h附錄B小測驗答案注:原文檔電子版(非掃描),需要的請下載本文檔后留言謝謝。第1章Java虛擬機Java虛擬機(JavaVirtualMachine,JVM)是一個可用于開發和部署軟件的現代平臺。顧名思義,最初開發它旨在支持使用Java語言編寫的應用程序,但設計Java的人不久就認識到,JVM不僅可運行Java語言,還可利用Java的功能和龐大的類庫。1995年,Sun公司1發布了Java和第一個JVM實現。鑒于其重點是網絡應用程序,Java很快就大行其道;它還被設計成可隨處運行。開發Java的初衷是用于機頂盒編程,但Sun公司發現彼時機頂盒市場還不成熟,因此決定同時將這個平臺推向臺式機。為此,Sun公司設計了一種獨特的二進制可執行格式,并稱之為Java字節碼。要運行被編譯成Java字節碼的程序,系統必須安裝JVM實現。1Sun公司于2009年4月被Oraele公司收購。——編者注本書將簡要地介紹5種最流行的JVM語言。通過學習這些語言的基礎知識,并動手編寫代碼,你將能夠做出判斷,確定哪種語言對你、你的團隊和項目來說是最合適的。我們先來說點實在的,到第2章再深入介紹Java開發包(JDK)和Java類庫。當前,可使用的編程語言和平臺眾多,它們相互爭奪市場,因此有必要先來詳細地說說JVM向開發人員提供了什么。有鑒于此,本章將介紹如下主題:為何要在JVM上進行開發;JVM的常見用途;JVM概念簡介;Java版本;其他JVM語言。1.1JVM實現需要指出的是,本書只考慮與OracleJavaSE8(和更高版本)兼容的JVM實現。這個版本可在臺式機、服務器和眾多單板計算機(包括尺寸如信用卡的所有RaspberryPi)上安裝。本書使用的是Oracle的JVM實現,你也可使用開源的OpenJDK和IBM的J9JavaSE實現。本書不涵蓋Google發布的用于Android手機和平板電腦的Java平臺,因為用于Android的Java版本基于較舊的Java版本。雖然用于Android的Java平臺版本越來越新,但它并未提供OracleJavaSE8的所有功能,且需要使用不同的編譯器和工具。另外,Google刪除了大量的JavaSEAPI,取而代之的是Google自己開發的不兼容的API。然而,本書介紹的有些語言也可用于Android開發。例如,Kotlin就是一種非常流行的Android開發語言,但本書不會對此展開討論。1.2為何要在JVM上開發當前,可供使用的編程語言和平臺眾多,為何要在JVM上開發和部署項目呢?因為JVM最初是為Java語言開發的,而近年來,其他語言的擁躉無數次地宣稱,Java語言已過時乃至死亡。近年來,流行的編程語言如走馬燈似的更換,而Java猶如常青樹,始終處于全球使用最多的編程語言排行榜的前列。JVM平臺為何如此強大呢?下面來看看其中一些最重要的原因:它適應市場的變化,從而確保與時俱進;內置的Java類庫非常強大;它有無可比擬的生態系統。1.2.1JVM適應市場的變化Java于20世紀90年代中期面世,那時的計算機裝備的都是單核CPU,內存量也沒有幾個GB,因為內存條貴得不得了。Java是與時俱進的語言之一:多核CPU面世后不久,Java就通過在多個線程中運行代碼來支持多核。但它并沒有就此止步,而是在每次推出新版本時,都添加了讓并發編程更容易的新類。這種做法到現在依然沒有停止。函數式編程范式大行其道后,Java在核心語言中新增了對lambda和流的支持。雖然Java提供這種支持的時間很晚,但相比于其他流行的語言,其實現更佳。這是因為程序員幾乎什么都不用做就能實現多線程。適應市場變化還意味著有時需要做減法。Java面世時,熱點是直接在瀏覽器中運行Java代碼。這些微型程序被稱為applet,要求瀏覽器和系統安裝專用的瀏覽器插件。而現在,市場已將JavaScript作為創建交互式網站的標準語言。有鑒于此,Oracle最近摒棄了applet標準。1.2.2Java類庫在每個Java版本(這將在本章后面更詳細地介紹)中,都指定了相應的JVM實現必須提供哪些類。JavaSE8的類庫包含大量的類,每個遵循JavaSE8平臺標準的JVM實現都必須實現這些類,而不管這種實現是由誰開發的。這個類庫中的類提供了諸如讀寫控制臺窗口、執行文件I/O以及與TCP服務器進行通信等功能,還有很多用于啟動和管理操作系統線程的類。更重要的是,還包含定義列表和映射(在有些語言中稱為字典)等眾多數據結構的類。下一章將詳細介紹Java類庫中的類。Java類庫是語言設計人員將JVM作為目標開發平臺的重要原因之一。有了這個類庫定義的數據結構后,他們能夠更專注于語言設計,而不用太專注于從頭開始打造完整的運行時庫。要知道,打造能夠與Java類庫媲美的、經過全面測試的、多平臺運行時系統類庫可是一項艱巨的任務。1.2.3生態系統顯然,內置的類庫不可能涵蓋程序員的所有用例。對于內置類庫缺失的東西,可求助于其他公司、組織和個人開發的庫和工具,以節省開發時間。鑒于很多年來Java都非常成功,其生態系統是無可比擬的,因此很難找到一個這樣的平臺,即其中可供選擇的工具、庫、工具包和框架比JVM提供的還要好。鑒于可供使用的插件庫眾多,開發人員的開發方向幾乎不會受到Java的限制。為說明Java生態系統有多豐富,我們來看看創建Web應用程序時,Java開發人員通常具有的選擇空間:創建在JVM應用程序服務器中運行的Web應用程序;為快速獲得結果,可使用通用的高級Web框架;為獲得更大的控制權,可使用微服務框架來創建應用程序。場景1:使用JVM應用程序服務器開發人員可以像企業那樣安裝基于JVM的應用程序服務器(這可以是開源的,也可以是付費的專用服務器),并使用它來運行應用程序和Web應用程序。這種服務器將負責處理配置問題以及管理數據庫連接。有簡單的應用程序服務器,它們只包含運行基本Web應用程序所需的內置API。但也有經過Oracle認證的功能齊備的應用程序服務器,它們提供了大量內置的標準化API,其中包括訪問數據庫的API、生成或使用XML和JSON文檔的API、按SOAP或REST標準與其他Web服務通信的API、確保Web安全的API、向遺留計算機系統發送消息或從這些系統接收消息的API等。下面是兩個最重要的企業開發框架:OracleJava企業版(JavaEE)平臺,這將在本書后面介紹;Spring框架生態系統(其中包括SpringBoot)。很多應用程序都結合使用了這兩種技術。下面是一些流行的應用程序服務器:ApacheTomcat(用于運行簡單的Web應用程序);ApacheTomEE;RedHatWildFly;OracleGlassFish;RedHatJBossEnterpriseApplicationPlatform;OracleWebLogic。其中前四個是開源的,而后兩個是專用的。場景2:使用高級的通用Web應用程序框架第二種選擇是使用完整的Web應用程序框架。相比于企業框架,這些框架提供的API通常更高級,它們還提供了內置的模型-視圖-控制器(model-view-controller,MVC)解決方案,可極大地提高開發人員的效率。使用這些框架時,開發人員的選擇通常受到限制,因為它們只支持為數不多的幾個庫和工具包。然而,它們支持添加插件來提供其他選擇。換而言之,使用這些框架是以放棄一些選擇空間來換取更短的開發周期。有些框架要求應用程序運行在JVM應用程序服務器中,而有些提供了自己的HTTP服務器。在這種框架中,ApacheStruts一度非常流行,但現在最流行的可能是Play。場景3:使用微服務框架另一種選擇是使用現代微服務框架來創建應用程序。這些框架提供了內置的HTTP服務器,可用于運行應用程序,但沒有提供其他任何現成的工具和庫。在這種情況下,更容易根據需要混合使用不同的庫和工具包。為了采用現代微服務架構,通常將應用程序分成多個獨立的Web服務,但這些框架并不要求你必須這樣做。最常用的微服務框架包括Vert.x和SparkJava,其中后者并非是用于ApacheSpark大數據平臺的。1.3常見的用途前面提供了一些證據,證明了JVM是切實可行的現代軟件開發平臺,下面來看看一些常見的JVM用途:Web應用程序;大數據分析;物聯網。1.3.1Web應用程序JVM非常重視性能,很多人都選擇使用它來開發Web應用程序。在設計正確的情況下,應用程序在需要跨越眾多不同服務器時的伸縮性極佳。JVM是一個大家了解得非常清楚的平臺,這意味著其行為是可預測的。另外,它還提供了很多工具,可用來調試和剖析有問題的應用程序。鑒于JVM是開源的,完全可以對其內部進行監視。對那些必須同時為數以千計的用戶提供服務的Web應用程序來說,這是一個非常重要的優點。JVM在云計算中扮演著重要的角色。Twitter、Amazon、Spotify和Netflix等很多著名公司都在其基于云的服務的核心部分使用了JVM。1.3.2大數據大數據是當前的一個熱點。在數據太大,無法使用傳統的數據庫進行分析時,可搭建多個數據庫集群來處理它們。大數據分析包括查找特定的信息、找出規律、計算統計指標等。這種數據可能是從Web服務器收集的數據(如已登錄用戶的單擊)、位于制造車間的外部傳感器的輸出、遺留服務器多年來生成的日志文件等。它們的規模各不相同,但通常多達數TB。下面是大數據領域兩種流行的數據分析技術。ApacheHadoop:負責存儲數據以及將數據分發到其他服務器。ApacheSpark:使用Hadoop對數據進行流化(stream),以便能夠對到來的數據進行分析。Hadoop和Spark都主要是使用Java編寫的。它們都提供了接口,以支持大量的編程語言和平臺,其中當然包括JVM。函數式編程范式致力于創建可在多個CPU內核中安全運行的代碼,因此進行Spark或Hadoop編程時,Scala和Clojure等純函數式編程語言是非常合適的選擇。1.3.3IoT當前,能夠連接到Internet的移動設備非常普及。鑒于Java最初就是為在嵌入式設備中運行而設計的,因此在IoT領域,JVM也處于優勢地位。對于內存有限的系統,Oracle提供了JavaMEEmbedded平臺。這種平臺是專門為不需要標準圖形(或基于控制臺的)用戶界面的商用IoT設備設計的。對于那些內存還算寬裕的設備,可使用JavaSEEmbedded版。JavaSEEmbedded與本書討論的JavaSE很像,在運行完整Linux的環境中,可使用它來提供桌面GUI,以支持全面的用戶交互。JavaMEEmbedded和JavaSEEmbedded平臺都能夠訪問RaspberryPi的通用輸入/輸出(general-purposeinput/output,GPIO)針腳,這意味著可通過Java代碼來訪問這些端口連接的傳感器和其他外圍設備。1.4JVM概念要有所作為,JVM開發人員必須熟悉下面這些最重要的JVM概念:JVM是一種虛擬機;JVM實現大都自帶即時(just-in-time,JIT)編譯器;JVM提供了一些內置的基本類型;除基本類型之外的其他一切都是對象;對象是通過引用類型來訪問的;垃圾收集器(garbagecollector,GC)進程將過期的對象從內存中刪除;JVM大量地使用構建工具。1.4.1虛擬機Java虛擬機是一種虛擬機,這一點顯而易見,但必須牢記在心。這意味著從理論上說,在一種計算機上開發的應用程序,可在另一種計算機上運行。一般而言,代碼在32位還是64位的Java運行時環境(JavaRuntimeEnvironment,JRE)中運行無關緊要。在64位的運行時環境中運行時,應用程序可使用的內存可能更多,但只要應用程序不執行原生操作系統調用或需要數GB的內存,這種差別就無關緊要。在C等語言中,數據類型的長度取決于原生系統,而Java不存在這樣的問題或特色(這是問題還是特色取決于你怎么看)。在JVM中,整型都是無符號的且長32位,而不管運行程序的是哪種計算機平臺或系統架構。最后,需要指出的是,在JVM中運行的每個應用程序都在系統內存中加載自己的JVM實例。這意味著同時運行多個Java應用程序時,每個應用程序都有自己的JVM副本;這還意味著在必要的情況下,不同的應用程序可使用不同的JVM版本。出于安全考慮,不建議在同一個系統中安裝不同的JDK或JRE版本;通常最好只安裝系統支持的最新版本。1.4.2JIT編譯器雖然沒有規定,但所有流行的JVM實現都并非只有簡單的解釋器:除解釋器外,它們還自帶了復雜的JIT編譯器。啟動Java應用程序時,將首先啟動并初始化JVM。JVM啟動并初始化后,它將立即開始解釋并運行Java字節碼。在合適的情況下,解釋器將對程序的某些部分進行編譯,再將原生可執行代碼加載到內存中,并開始執行這些代碼而不是經過解釋后的Java字節碼。這樣生成的代碼的執行速度通常要快得多。對代碼進行編譯還是解釋取決于很多因素。對于經常被調用的例程,JIT編譯器很可能對其進行編譯以生成原生代碼。JIT方法的優點在于,分發的文件可以是跨平臺的,且用戶無需等待整個應用程序編譯完畢。JVM初始化后,應用程序將立即開始執行,而優化是在幕后完成的。1.4.3基本數據類型JVM提供了幾個內置的基本數據類型,這是Java未被視為純粹的OOP語言的主要原因。這些類型的變量不是對象,且始終都包含值。Java名稱描述和長度取值范圍(含)byte有符號字節(8位)-128~127short有符號短整型(16位)-32768~32767int有符號整型(32位)-231~231-1long有符號長整型(64位)-263~263-1float單精度浮點數(32位)不精確的浮點值double雙精度浮點數(64位)不精確的浮點值char單個UnicodeUTF-16字符(16位)Unicode字符0~655535boolean布爾值True/False請注意,并非所有JVM語言都支持創建基本類型變量,并將其他一切都視為對象。你將看到,這通常不是問題,因為Java類庫包含包裝基本類型的包裝對象,而包含Java在內的大多數語言都會在必要時自動使用這些包裝對象。這個過程被稱為自動裝箱(auto-boxing)。1.4.4類函數和變量都是在類中聲明的。即便是應用程序的入口函數(在程序啟動時調用的函數main())也是在類中聲明的。JVM只支持單繼承模型,即類最多繼承一個類。這影響不大,因為使用了名為“接口”的結構來緩解這種影響,你將在下一章看到。接口基本上是一個函數原型(只有函數的定義,而沒有代碼)和常量列表,編譯器要求實現了接口的類必須提供這些函數的實現。類可實現任意數量的接口,但必須提供這些接口定義的每個方法的實現。本書介紹的有些語言對開發人員隱藏了上述事實。例如,不同于Java,有些語言允許在類聲明外面定義函數和變量,甚至允許可執行代碼位于函數定義外面。還有些語言支持繼承多個類。在內部,這些語言巧妙地規避了JVM的限制和設計決策。JVM類通常以包的方式進行分組。在下一章,你將看到類是如何組織的。1.4.5引用類型與大多數現代編程語言一樣,JVM不直接操作指向對象的內存指針,而使用引用類型。引用變量要么指向特定的類實例,要么什么都不指向。如果一個引用變量指向特定的對象,就可使用它來調用該對象的方法或訪問其公有屬性。如果一個引用變量沒指向任何東西,就被稱為空引用(nullreference)。使用空引用來調用方法或訪問屬性時,將在運行階段引發錯誤。對于這個常見的問題,本書介紹的有些語言提供了解決方案。引用和空引用請看下面的代碼:Productp=newProduct();p.setName("Boxofbiscuits");假設這里的Product是當前程序可使用的一個類。我們創建一個Product實例,并讓變量p指向它。接下來,我們對這個對象實例調用方法setName。JVM沒有提供直接訪問這個Product對象所在內存單元的途徑,而只提供了指向該對象的引用。當你使用變量p時,JVM將確定為訪問這個變量指向的對象,需要訪問哪個內存單元。我們在前述代碼片段中添加如下代碼行:p=null;p.setName("Thislinewillproduceanerroratrun-time");可顯式地將引用設置為null。請注意,對于在方法內聲明的變量,并非必須這樣做,因為方法結束時,將自動清理這些變量,但這樣做也是完全合法的。現在變量p是一個空引用。下一段將介紹對象實例不再被任何引用變量指向后將發生的事情。上述代碼能夠通過編譯,但程序運行時,最后一行將引發NullPointerException異常。如果沒有提供錯誤處理功能,應用程序將崩潰。很多現代IDE都力圖發現這種情形,并向開發人員發出警告。1.4.6垃圾收集器JVM不要求程序員在創建和銷毀對象時手工分配和釋放內存塊。通常,程序員只需在需要時創建對象即可。有一個名為GC的進程,它每隔一段時間讓應用程序停止執行,并在內存中掃描不再在作用域內的對象(不能被任何對象訪問的對象),再將這些對象從內存中刪除,并收回釋放的內存空間。以前,這個進程會導致嚴重的性能問題,但它使用的算法已得到極大的改進。另外,根據應用程序的需求,系統管理員可配置GC的眾多參數,以更好地控制它。開發人員應始終牢記GC算法。如果你不斷地創建大量的對象,并確保它們位于作用域內(即讓所有這些對象都是可訪問的,如將它們存儲在應用程序可訪問的列表中),那么遲早會導致內存耗盡,進而引發錯誤。示例假設你為一個在線商店開發了一個電子商務應用程序,同時假設每位已登錄的用戶都有一個ShoppingBasket實例,其中存儲了該用戶已加入到購物車中的商品。現在假設今天有一位已登錄的用戶,他打算購買一塊香皂和一盒餅干。對于這位用戶,應用程序將創建兩個Product實例(每件商品一個),并將它們添加到ShoppingBasket的products列表中,如下圖所示。結賬前,這位用戶發現Amazon也有這樣的餅干,但價格低得多,因此決定將其從購物車中刪除。從技術上說,應用程序將從products列表中刪除相應的Product實例。但這樣做后,表示Chocolatecookies的Product實例就成了孤兒對象。鑒于沒有任何引用指向它,應用程序再也無法訪問它,如下圖所示。過段時間后,JVM的GC啟動,它發現應用程序無法訪問表示Chocolatecookies的Product對象,因此決定將其刪除,從而釋放它占用的內存,如下圖所示。為避免GC將對象刪除,有多種技巧。其中一個著名的技巧是,在應用程序需要使用大量類似的對象時,將這些對象放在一個對象池(對象列表)中。在應用程序需要對象時,只需從池中取回一個,并根據需要修改它。使用完畢并不再需要該對象時,將其放回到對象池中。由于這些對象始終在作用域內(未用時,這些對象位于應用程序能夠訪問的對象池中),GC不會銷毀它們。1.4.7向后兼容負責維護JVM和Java類庫的人深知企業開發人員的需求:現在編寫的代碼最好以后也能運行。在向后兼容方面,JVM做得很不錯;如果你熟悉Python2和Python3,就知道情況并非總是如此。較新的JVM版本能夠運行針對較舊的JVM版本編譯的應用程序,條件是應用程序沒有使用在較新的JVM版本中已刪除的API或技術。例如,在Java8JVM實例上運行的項目可加載并使用針對Java6編譯的庫,但反過來行不通,即在Java6JVM實例上運行的應用程序不能加載針對更高版本編譯的類。當然,與其他平臺和語言一樣,負責維護JDK和Java類庫的人必須時不時地摒棄一些類和技術。在向后兼容性方面,JVM雖然存在問題,但總體而言比眾多其他的平臺和語言要好得多。另外,通常僅當有合適的替代品后,才會將API刪除。1.4.8構建工具在項目比較簡單的年代,為自動化編譯和打包過程,使用的是簡單的批文件或操作系統shell腳本文件。隨著項目越來越復雜,定義這樣的腳本越來越難。另外,對于不同的操作系統,必須編寫完全不同的腳本。不久后,第一套專用的Java構建工具應運而生。它們使用的是XML構建文件,讓你能夠編寫跨平臺的腳本。最初,必須編寫冗長而繁瑣的腳本;但后來,這些工具采用了約定優先于配置的范式。遵循這些工具指定的約定時,需要編寫的代碼少得多;但如果你面對的不是默認情形,可能需要花很大的精力來讓工具按你希望的做。為自動化構建過程,較新的工具放棄了XML文件,轉而提供了腳本語言。在這些工具中,很多都提供了如下功能。內置的依賴管理器:能夠從著名的網絡倉庫下載附加庫。自動運行單元測試,并在測試失敗時停止打包。JDK本身沒有提供構建工具,但幾乎每個項目都至少使用了下面一個開源的構建自動化工具。ApacheAnt(沒有內置的依賴管理器,使用的是基于XML的構建腳本)。ApacheMaven(通過使用XML文件引入了約定優先于配置的原則,并使用插件)。Gradle(構建腳本是使用Groovy或Kotlin編寫的)。只要使用的是流行的IDE,JVM程序員就無需過多地考慮構建自動化工具,因為所有IDE都能夠生成構建腳本。如果要獲得更大的控制權,可手工編寫腳本,并讓IDE根據你編寫的腳本來編譯、測試和運行項目。1.5Java版本Java有多個不同的版本,其中每個版本都針對不同的用例。多年來,有些版本的名稱發生了翻天覆地的變化,當前版本的名稱如下:Java標準版(JavaSE)Java企業版(JavaEE)Java微型版(JavaME)1.5.1JavaSE這是最重要的版本,大家說到Java時,通常指的是就是這個版本。本書只考慮JavaSE平臺。這個版本用于臺式機和服務器。另外,你將看到,還有一個嵌入式版本,用于RaspberryPi的Linux發行版就自帶了這種嵌入版本。JavaSE自帶了完整的Java類庫,還包含經典的SwingGUI工具包,而大多數版本還包含較新的JavaFXGUI工具包。注意:較新的JavaSEEmbedded更新刪除了JavaFX工具包。在RaspberryPi上安裝這個更新后,JavaFX組件將消失。Oracle以開源的方式提供了用于RaspberryPi的JavaFX,讓高階用戶能夠下載并編譯它。JavaSE主要用于創建獨立的控制臺應用程序、桌面GUI應用程序和無界面(headless)應用程序,還可用于創建外部庫。1.5.2JavaEEJavaEE建立在JavaSE的基礎之上,因此要求安裝JavaSE。它添加了類型眾多的API。JavaEE應用程序通常運行在JVM應用程序服務器上。本書不會深入介紹JavaEE,但時不時會提及它,因為它是Java平臺的重要補充,對企業開發人員來說尤其如此。Oracle網站沒有提供獨立的JavaEE版本,你必須下載與所需JavaEE平臺版本兼容的應用程序服務器。有些IDE也自帶了JavaEE應用程序服務器,這將在下一章討論。JavaEE標準只描述了必須提供的API,而沒有指定實現方式。具體如何實現符合標準的API,由與JavaEE兼容的應用程序服務器決定。示例:兩款應用程序服務器實現的Java持久化APIJavaEE描述了Java持久化API(JavaPersistenceAPI,JPA)。這是一個對象關系映射器(objectrelationmapper,ORM)API,位于Java對象和關系型數據庫(通常是SQL數據庫,如Oracle、OracleMySQL、PostgreSQL等)之間;使用它只需編寫幾行代碼,就可將JVM對象的內容寫入數據庫,反之(從數據庫讀取數據并將其加入對象中)亦然。Oracle提供的JavaEE參考實現是一個開源的應用程序服務器,名為GlassFish。GlassFish包含開源項目EclipseLink,該項目實現了JPA標準。RedHat出品的WildFly也是一款開源的JavaEE應用程序服務器,其中包含RedHat自己開發的ORM開源項目Hibernate,這個項目也實現了JPA標準,但更流行。如果只使用JPA標準規定的功能,則使用哪種實現無關緊要,但要使用其他功能,選擇使用哪種實現就很重要。如果你不喜歡某個應用程序服務器廠商的設計決策,通常可轉而使用其他實現。對于選擇空間,JVM開發人員非常在乎!1.5.3JavaME在iOS和Android面世前,JavaME是重要的功能手機和智能手機游戲和應用程序開發平臺。iOS和Android都不支持JavaME應用程序,因此它現在已不再是主角。JavaME包含Java類庫的一部分,同時提供了其他一些與移動設備交互的API。JavaME獲得了重生,它現在名為JavaMEEmbedded,可用于商業IoT設備。1.6其他JVM語言為推廣Java語言和平臺,Sun很早就公布了JVM規范。這個文檔旨在供那些要自己動手編寫JVM實現的開發人員參考,這些JVM實現可能是為那些沒有官方JVM實現的平臺編寫的。這個文檔描述了JVM可執行的低級命令、必須提供的數據結構、內存訪問規則、Java字節碼文件格式.class等。這個規范的發布讓其他語言的設計者能夠嘗試Java字節碼,因此不久后其他語言也能夠編譯成這種格式。這雖然不是Java設計者的初衷,但Sun(和后來的Oracle)樂見其成。它們是如此地樂見其成,以至于僅僅為方便JVM支持動態語言而添加了新功能。本節將介紹與其他JVM語言相關的如下主題。為何要放棄Java轉而使用其他語言進行JVM開發?在同一個項目中使用多種語言的可能性以及這樣做可能帶來的問題。使用不同于主項目使用的語言編寫單元測試。1.6.1為何選擇其他語言考慮到Java語言最初就是為在JVM上運行而設計的,怎么會有人選擇使用其他語言來進行JVM開發呢?開發人員這樣做的原因有多個:Java是一種非常繁瑣的語言;并非所有人都喜歡靜態類型語言,且靜態語言并非在任何情況下都是最佳選擇;Java類庫缺少一些經常需要用到的類。Java是一種非常繁瑣的語言Java以繁瑣著稱。經過多年的修訂后,Java已不再那么繁瑣,但使用很多其他的語言時,完成同樣的任務所需的代碼更少。我們來看一個簡單的示例。在Java中,標準的可修改對象通常類似于下面這樣:classPerson{privateStringname;publicPerson(Stringname){=name;}publicStringgetName(){returnname;}publicvoidsetName(Stringname){=name;}}而使用Kotlin時,只需下面一行代碼就能實現同樣的功能(以及其他功能):dataclassPerson(valname:String)這可不是開玩笑。編譯這行代碼時,Kotlin將自動實現Java示例中定義的方法;實際上,它還會添加其他較為常用的方法。第4章將討論這些額外的方法。雖然使用其他語言可極大地提高效率,但Java也沒有看起來那么糟糕。所有現代IDE編程工具都能自動生成Java樣板代碼,如前述示例中的樣板代碼。為此,你只需按下一個簡單的組合鍵即可。Java并非對所有的人或在任何情況下都是理想選擇雖然Java8新增了一些重要的函數式編程功能,但從本質上說,它依然是一種靜態的命令式語言。并非所有的開發人員都喜歡這種編程風格。如果必須使用靜態語言來編寫代碼,Python或Ruby程序員可能會哭暈在廁所。有鑒于此,有些團隊放棄Java轉而選擇使用其他語言來進行JVM開發。另外,對于有些問題,使用動態編程語言解決起來要優雅得多;同時對于必須執行復雜并發操作的項目來說,函數式編程風格通常更合適。最后,對于有些哭和框架,通過某些語言來使用讓人感覺更為自然。Java類庫缺失的類Java類庫是一個龐大的庫,但它畢竟是20多年前推出的,因此在有些情況下缺少必要的類。在大多數情況下,功能缺失的問題可通過添加JVM生態系統中免費的開源插件庫來解決,但如果選擇使用內置了這些功能的語言,不僅更方便,還可節省時間。例如,對于極其常用的JSON標準,JavaSE8的Java類庫就沒有提供原生支持。流行的插件庫Jackson和GoogleGSON提供了JSON支持;另外,較新的JavaEE平臺版本也提供了支持JSON的API。本書介紹的一些語言提供了原生的JSON支持。另一個問題是,要使用Java類庫中的一些常用類,必須編寫大量的樣板代碼。對于Java類庫中的眾多常用類,諸如Groovy等語言都提供了包裝器,讓這些API使用起來輕松得多。1.6.2在同一個項目中使用多種JVM語言很多語言都能夠與Java互操作,因此也能夠與其他JVM語言互操作。這是通過盡可能為數據結構使用標準Java類庫并像Java那樣編譯方法來實現的。在Java項目中,經常使用其他語言來編寫某些類,但這樣做可能帶來一些問題:構建過程將復雜得多;很多語言要求使用自己的運行時類,這可能帶來問題。構建過程更復雜使用多種語言時,必須調整構建腳本,這可能導致情況非常復雜。例如,如果Java項目使用了用Groovy編譯的類,編譯順序將非常重要,即必須先編譯Groovy類,再編譯Java代碼。如果Groovy代碼使用了Java項目中的自定義類,情況將更加復雜。你將在第11章看到,Groovy比較特殊。Groovy編譯器能夠編譯大部分Java代碼,因為從很大程度上說,Groovy語言與Java語言兼容。在沒法這樣做或這樣做不可取時,有一個用于構建工具ApacheMaven的編譯器插件,使用它可解決構建過程中面臨的問題。一種解決之道是將代碼分成多個子項目,并在構建工具中將生成的庫作為主項目的需求列出。有些語言提供了另一種解決方案:它們提供了自定義類,讓你能夠在Java(或其他JVM語言)中調用這些語言的源代碼。被這些類加載時,源代碼將動態地編譯為Java字節碼。其他語言實現了在Java代碼中嵌入腳本語言的官方標準;附錄A討論Oracle的JavaScript解釋器Nashorn時,將簡要地討論這一點。語言運行時庫從某種程度上說,這與構建并發癥相關。很多JVM語言都要求在編譯后的程序中包含支持庫,這些庫通常定義了語言特有的數據結構以及編譯得到的Java字節碼調用的內部支持方法。這通常不是問題,但如果項目的依賴項(或依賴項的依賴項)是使用不同的語言版本編寫的,就可能出現問題。如果同一個項目的多個庫要求使用同一個運行時庫的不同版本,情況將更為復雜:編譯或運行項目時,可能出現令人費解的錯誤消息。這被稱為依賴惡夢(dependencyhell),但這并非是在同一個項目中使用多種語言特有的現象,而是每個開發人員都應知道的現象。打算在同一個項目中使用多種語言的開發人員還必須明白,語言運行時庫可能導致最終程序的規模急劇增大;有些運行時庫還包含其依賴項,這將增大出現依賴惡夢的風險。通常,語言的文檔或官網都詳細說明了其依賴項。與很多框架設計者一樣,很多語言設計者都對這些問題心中有數,并采取了措施降低這些問題出現的風險。例如,對于自己使用的較流行的依賴項,他們進行了重命名,以防發生類名沖突。1.6.3使用另一種語言編寫單元測試使用其他語言編寫的單元測試來對Java代碼進行測試很常見。正如你在本章前面看到的,相比于Java,使用其他語言編寫的代碼可能緊湊得多,這些語言非常適合用來編寫小型、具體而易于理解的單元測試。鑒于僅在運行單元測試時才會用到這些語言的運行時庫,因此無需在編譯得到的主項目中包含它們。你將在第11章看到,在這樣的情形下,非常適合使用Groovy。Groovy提供了一些便利的單元測試編寫功能,其中包括內置的assert語句,這種語句在傳入的值與期望值不同時將打印非常詳盡而易于理解的輸出。。1.7小結本章非常簡略地描述了JVM。首先介紹了JVM向開發人員提供的功能、JVM的常見用途以及最重要的JVM概念;接下來探索了Java版本;最后介紹了其他JVM語言,以及開發人員放棄Java轉而使用其他語言進行JVM開發的原因。在下一章,我們將安裝并詳細介紹JDK,還將詳細介紹Java類庫并安裝其他開發工具,為動手開發做好準備。第2章Java虛擬機開發本章深入介紹Java虛擬機(JVM),重點是每個JVM開發人員都必須知道的概念,而不管他選擇使用的是哪種編程語言。本章涵蓋如下主題:Java開發包(JDK);使用包來組織類;Java類庫;從命令行運行JVM應用程序;安裝Eclipse集成開發環境(EclipseIDE)。本書涵蓋Windows、macOS和Linux(Ubuntu)操作系統,但展示路徑時通常使用Windows風格。如果你使用的是macOS或Linux,務必按相應操作系統的規則修改路徑。2.1JDK要進行JVM開發,必須安裝JDK。JDK包含Java運行時環境(JavaRuntimeEnvironment,JRE)、Java編譯器以及各種開發工具(本章將介紹其中的一些)。即便你的大部分開發工作都將使用其他語言而不是Java來完成,也強烈建議你安裝完整的JDK,因為很多重要的開發工具都必須安裝完整的JDK才能運行。另外,你遲早都將用到一些只有JDK才有的工具。安裝較新的用于RaspberryPi的Linux發行版時,如果使用默認的Raspian安裝選項,將自動安裝JavaSEEmbedded8JDK,但提供的版本通常不是最新的。其他主要的操作系統默認安裝的JDK如何不得而知。本節介紹如下與JDK相關的主題:安裝JDK(Windows、macOS和Linux);探索JDK;JRE。2.1.1安裝JDK這里只介紹如何安裝Oracle的JDK8實現。如果你已安裝與JavaSE8平臺完全兼容的JDK實現,包括開源的OpenJDK8或IBM的J9JDK8,通常也完全可行,因此你可以跳過本節。非Oracle的JDK實現并不一定包含本書討論的所有功能,必要時我們將指出例外情況。無論你使用的是哪種操作系統,都必須創建一個名為JAVA_HOME的環境變量,并讓它指向JDK安裝目錄(在非開發計算機中為JRE所在的目錄)。對于本書涵蓋的操作系統(Windows、macOS和Linux),我們將說明如何創建這樣的環境變量。很多重要的JVM工具都要用到這個變量,包括構建工具和應用程序服務器。本節將介紹如何完成如下工作:下載JDK;在Windows系統中安裝JDK;在macOS系統中安裝JDK;在Linux系統中安裝JDK;下載JavadocAPI文檔。下載JDKOracle提供的用于Windows、macOS和Linux的JDK實現可從Oracle網站下載。對于有些平臺,只有64位的JDK,而對于其他平臺,有32位和64位的。使用你喜歡的瀏覽器訪問Oracle的Java主頁(\h/java),如下圖所示。要下載JDK,需執行如下步驟。(1)本書編寫期間,該網頁包含一個JavaforDevelopers,單擊該按鈕將進入SoftwareDownloads部分。(2)在列表中找到并單擊JavaSE(包含JavaFX)。如果它旁邊有鏈接EarlyAccess,請注意不要單擊該鏈接。(3)進入JavaSEDownloads頁面。單擊JDK下方的Download按鈕。(4)根據你使用的操作系統平臺和體系結構,找到并單擊相應的版本。(5)如果你同意了許可條款,將下載相應版本的JDK。在Windows系統中安裝JDK對于Windows操作系統,JDK有32位和64位的版本。你只需運行下載的可執行文件并按說明做即可。請將JDK安裝路徑記錄下來,因為后面要用到。請使用默認設置,這將隨JDK安裝JRE。強烈建議確保JRE和JDK的版本同步,因此使用JDK安裝程序安裝JRE是最佳選擇。Oracle指出JDK始終是在系統級安裝的,因此其他所有用戶都可使用它。安裝完畢后,需要添加或修改一些環境變量。這里介紹如何在Windows10中這樣做,如果你使用的是其他較新的Windows版本,做法應與之類似。(1)右擊Windows“開始”按鈕并選擇“系統”,在出現的窗口中,單擊左邊的“高級系統設置”。(2)這將打開“系統屬性”對話框。單擊“環境變量”按鈕,這將打開如下圖所示的“環境變量”對話框:(3)在這個對話框底部的“系統變量”部分查找變量JAVA_HOME。如果沒有找到,就單擊按鈕“新建”,否則對既有的JAVA_HOME進行編輯。(4)將變量名設置為JAVA_HOME,并將值設置為JDK安裝目錄的完整路徑,再單擊“確定”按鈕關閉打開的對話框。(5)找到既有的變量Path,并在其中添加JDK安裝目錄下的子目錄bin的完整路徑;別忘了用字符;將不同的目錄分隔。為驗證安裝,可執行如下步驟。(1)打開一個命令提示符窗口(為此,可單擊“開始”按鈕,輸入cmd并按回車鍵)。(2)輸入javac-version并按回車鍵。你將看到一個版本號,它與下載的JDK版本相同。如果不是這樣,請核實你是否正確地修改了環境變量,并確保你新打開了一個命令提示符窗口,而不是使用以前打開的命令提示符窗口。在macOS系統中安裝JDK請注意,要安裝JDK,使用的macOS版本必須是較新的。在本書編寫期間,JDK8要求macOS版本至少為10.8(MountainLion)。在macOS系統中安裝JDK很容易,只需雙擊下載的映像(.dmg)文件,再在出現的Finder窗口中雙擊包圖標,然后按說明做即可。與Windows系統中一樣,在macOS系統中,JDK也是在系統級安裝的,因此可供所有用戶使用。安裝完畢后,需要確保新安裝的JDK是默認使用的JDK。macOS支持同時安裝多個JDK版本,你可在不同的版本之間切換,但只有一個版本處于活動狀態。要切換到新安裝的JDK版本,最簡單的辦法是打開位于你的Home文件夾中的文件.bash_profile(請注意這個文件名以句點打頭),并在其中添加如下行:exportJAVA_HOME="$(/usr/libexec/java_home-v1.8)"要驗證安裝,可執行如下操作:打開一個新的Terminal窗口;在其中輸入javac-version并按回車鍵。顯示的版本號應與你下載的JDK版本相同。在Linux系統中安裝JDKLinuxJDK有32位和64位版本,可以如下格式下載它們:下載壓縮的.tar.gz文件,用于手動安裝;下載RPM包管理器(RPMPackageManager)文件(.rpm),用于在支持這種打包格式的Linux中安裝JDK。Oracle認證了多個可安裝JDK的Linux發行版。在本書編寫期間,各種OracleLinux、RedHat和Ubuntu都通過了認證。即便你使用的不是這些Linux發行版,也并不意味著你的計算機不能運行JDK和JVM,而只是意味著沒有得到Oracle的官方支持。本節只介紹如何在Ubuntu系統中安裝JDK。Ubuntu沒有提供原生的RPM格式支持,因此如果你使用的是Ubuntu,推薦下載.tar.gz文件。在Linux系統中,雖然并非必須在系統級安裝JDK,但這里將這樣做。如果你使用的Linux發行版支持RPM或不支持后面用到的一些命令,請參閱JavaSEDownloads頁面中的鏈接InstallationInstructions。打開一個新的Terminal窗口,切換到下載的.tar.gz文件所在的目錄,并輸入如下命令:sutarxvfzjdk-VERSION-linux-x64.tar.gzlsmvjdk1.VERSION/usr/local/對這些命令說明如下。這要求你有系統根密碼。如果沒有這樣的密碼,請將su替換為sudo-s,但僅當你有根權限時,命令sudo-s才管用。必須將VERSION替換為你下載的JDK的版本號。這里假定平臺是64位的(x64),如果你下載的是32位版本,請將x64替換為i586。請注意,在最后一個命令中,你移動的是從下載的文件.tar.gz解壓縮得到的目錄(而不是這個文件本身)。另外,VERSION格式的目錄不同于下載的文件。請將/usr/local/jdk1.VERSION的完整路徑復制到剪貼板或記錄下來,因為下一步需要用到。現在來設置環境變量JAVA_HOME。我們希望Terminal為每位用戶自動加載這個環境變量:nano/etc/profile滾動到這個文件末尾,并添加如下內容(將JAVA_HOME=后面的內容替換為前面復制到剪貼板中的路徑):JAVA_HOME=/usr/local/jdk1.VERSIONexportJAVA_HOME按Cltrl+X并選擇Y來保存所做的修改,再按回車確認文件名。最后,你需要向Ubuntu注冊JDK和JRE命令。通過在Terminal窗口中輸入如下命令,將為兩個最重要的命令創建合適的符號鏈接:java(用于運行JVM應用程序)和javac(用于運行Java編譯器):./etc/profileupdate-alternatives--install"/usr/bin/java""java"$JAVA_HOME/bin/java1update-alternatives--install"/usr/bin/javac""java"$JAVA_HOME/bin/javac1其中第一個命令重新加載修改后的文件/etc/profile,以便能夠使用變量JAVA_HOME。請注意這個命令開頭的句點。如果要使用JDK子目錄bin中的其他命令,對于每個這樣的命令,都必須以根用戶的身份在Terminal中執行相應的update-alternatives命令。執行命令exit兩次將Terminal窗口關閉,再重新打開Terminal窗口(這次無需根權限),并輸入如下命令來驗證安裝:javac-version如果一切順利,將出現與下載的JDK版本相同的版本號。下載API文檔Oracle提供了完整的Java類庫API在線文檔。對于Java8,要查看這種文檔,可訪問\h/javase/8/docs/api/。在本地有該文檔的副本很有幫助,Oracle認識到了這一點并提供了下載。訪問JavaSEDownloads頁面(有關如何訪問這個頁面,請參閱“下載Download”一節)。找到AdditionalResources部分,并單擊JavaSE8Documentation旁邊的Download按鈕。如果你接受許可協議,就可下載相應的ZIP文件。將這個文件解壓縮到方便的位置,再使用你喜歡的瀏覽器打開子目錄docs中的文件index.html。如果你要使用工具包JavaFX創建桌面GUI應用程序,也應從這個下載頁面下載JavaFXAPI文檔。2.1.2探索JDKJDK最重要的組件如下:java(用于運行編譯后的JVM應用程序,即便這種應用程序不是使用Java編寫的);javac(Java語言編譯器)。JDK并非只包含這兩個組件;本節將介紹JDK的目錄結構并概述目錄bin中最重要的命令。目錄結構要熟悉JDK,了解其目錄結構大有裨益。下面以圖形方式概述了JDK安裝目錄包含的子目錄:下表更詳細地說明了這些子目錄。目錄名描述bin子目錄bin包含JDK提供的所有可執行命令,接下來將討論其中最重要的命令db與JavaDB組件相關的東西都存儲在這里。JavaDB是Oracle支持的數據庫項目ApacheDerby,這是一個開源的基于文件的關系數據庫系統,提供了強大的SQL支持。它完全是使用Java實現的。JDK9刪除了這個組件,但感興趣的讀者依然可以從Derby網站(\h/derby/)下載它include這個目錄是為高級程序員準備的,其中包含供C語言編譯器使用的頭文件,可在Java代碼中使用它們來調用隨平臺或操作系統而異的原生代碼,或反之jre這里存儲了所有與JRE相關的文件,包括Java類庫。請注意,目錄jre/bin中的所有命令也都包含在JDK安裝目錄下的子目錄bin中lib這里存儲了供一些開發工具使用的庫JDK命令目錄bin包含JDK提供的主要的命令行驅動命令。下表列出了其中最重要的命令,但并非所有這些命令都會在本書中做進一步的討論。可執行的命令描述java加載一個JVM實例并啟動在命令行中指定的程序,本章后面將更詳細地討論它。在Windows系統中,它將在運行應用程序時打開一個控制臺文本窗口javac這是Java語言編譯器javadoc從Java源代碼文件中提取并生成文檔,將在下一章簡要地討論javap對編譯后的Java代碼進行反匯編,生成類似于Java字節碼的易于理解的文本格式javaw只有Windows版JDK和JRE提供了這個命令,它與命令java相同,但不會打開額外的窗口。如果啟動的應用程序有桌面GUI,應用程序仍將在獨立的窗口中打開jar用于創建JAR歸檔文件、從JAR歸檔文件中提取數據以及在其中添加文件的工具。JAR歸檔文件將在本章后面更詳細地介紹jarsigner通過添加數字簽名來保護JAR文件。如果JAR文件的數據被修改,但簽名沒有相應地更新,文件將被視為無效的jdeps輸出編譯得到的.class文件或JAR文件的依賴信息jjs激活OracleNashorn的交互式解釋器shell。Oracle的JavaScript解釋器為Nashorn,將在附錄中討論請注意,目錄bin還包含這里沒有列出的其他命令,它們大都僅供高級用戶使用。GUI監視工具子目錄bin中包含上表未列出的三個工具,這里有必要說一說。不同于其他命令,這些命令提供了完整的桌面GUI:JavaVisualVM;OracleMissionControl;JConsole。只有Oracle的JDK實現包含這三個工具。開源實現OpenJDK不包含OracleMissionControl,而IBMJ9JDK不包含上述任何工具。(1)JavaVisualVM在8.0版之前,OracleJDK和OpenJDK都包含Java工具VisualVM。VisualVM是一個開源工具,用于監視所有運行JVM應用程序的JVM實例,你可以通過安裝插件來進一步改進其內置功能。如果你使用的是OracleJDK9或OpenJDK9,可以從\hhttps://visualvm.github.io/index.html下載這個開源工具。要使用默認設置啟動VisualVM,可執行如下命令:jvisualvm這將首先出現一個啟動窗口,過段時間后再出現VisualVM主窗口。VisualVM不僅能夠連接到網絡服務器上運行的JVM實例,還能連接到本地運行的JVM實例。在下面的屏幕截圖中,監視的是本地運行的NetBeansIDE實例:要設置JVM實例以便進行遠程監視,需要費點勁,這不在本書的討論范圍內,但JDK文檔的VisualVM部分做了詳細說明。實時監控將消耗大量的系統資源。僅當在開發環境中才應考慮對本地進程進行監控。遠程監控消耗的服務器資源要少些,但也相當可觀。(2)OracleMissionControl較新的OracleJDK版本都自帶了OracleMissionControl,這也是一個監視JVM實例和應用程序的工具。OracleMissionControl提供的用戶界面比JavaVisualVM還好,但很多功能都與VisualVM類似,包括實時監控正在運行的JVM實例和應用程序。OracleMissionControl是款專用軟件,其許可條款比較復雜。其大部分功能都可在開發和生產環境中免費使用,但其獨特的功能JavaFlightRecorder只能在開發環境中免費使用。要在生產環境中使用JavaFlightRecorder,必須有付費從Oracle獲得的許可密鑰。要運行OracleMissionControl,可執行如下命令:jmc通過使用JavaFlightRecorder,可記錄JVM在指定時段內發生的事件。記錄過程結束后,可對記錄的所有數據進行分析。JavaFlightRecorder的優點在于,開銷比OracleMissionControl和VisualVM的實時監控功能都低得多,因此在生產系統中使用它要安全得多(但別忘了其許可條款)。在下面的屏幕截圖中,使用FlightRecorder對NetBeansIDE進程監視了1分鐘。(3)JConsoleJConsole是最古老的監視工具,JDK在很久前就提供了它。相比于JConsole,JavaVisualVM和OracleMissionControl提供的功能都更豐富,GUI也更友好,因此建議你不要使用JConsole,而使用其他工具。如果你一定要使用JConsole,可使用如下命令來啟動它:jconsole2.1.3JRE如果只想在計算機上運行Java程序,可只安裝JRE,這將安裝用于啟動JVM實例的命令java以及完整的Java類庫。JRE用于啟動使用Java或其他語言編寫的應用程序。使用默認設置安裝JDK時,將同時安裝JRE。僅在不需要開發工具的計算機上,才需要單獨下載并安裝JRE。使用較舊OSX(在Apple將其重命名為macOS之前)的Mac計算機通常預安裝了Java運行時,但現在情況不再如此,因為Oracle已從Apple手工接管了macOSJavaSE實現的開發工作。Oracle網站提供了兩個版本的JavaSE8JRE:JREServerJREJRE用于32位或64位最終用戶臺式機(請注意,并非所有平臺都有32位版本),而ServerJRE用于服務器,通常由高級系統管理員安裝。ServerJRE只能用于64位系統,不包含安裝程序和瀏覽器插件,但包含前面討論的JVM監視工具。2.2使用包組織類所有JVM語言都定義了其創建類和實例化對象的語法,但它們生成的類文件最終都將在JVM上運行。為了能夠在JVM上運行以及與使用其他JVM語言編寫的類互操作,必須遵循JVM在類組織方面的要求。本節將討論如下主題:包;選擇包名;包名舉例;全限定類名。要明白Java類庫的組織方式以及如何從命令行運行JVM應用程序,必須對包有所了解。這兩個主題都將在本章討論。2.2.1包是什么本書介紹的語言大都支持將類組織成包。位于同一個包中的類構成了一個獨特的命名空間,這是JVM最重要的特征。有些語言本身不支持將類組織成包,但支持引用包中的類。一個這樣的例子是Oracle的JavaScript解釋器Nashorn。JavaScript語言本身不支持包,但Nashorn能夠導入放在包中的Java(或其他兼容)類。為演示如何將類組織成包,下面再來看看電子商務應用程序中購物車的實現,但這里的示例將更成熟些。JVM提供了一種對類進行組織的方式——將它們放在包中。通過這樣做,可將主題相同的類編組。就剛才的示例而言,將涉及的類放在下面這些包中比較合理。包包中的類basketBasket、BasketLineproductProductuserUser之所以選擇這種組織方式,是因為我認為這些類的主題分別為購物車、商品和用戶。另外,我預計未來Basket、Product和User類將被其他類使用,而BasketLine類只會在Basket類內部使用。通過使用包,不僅可讓大型項目的結構更容易理解(這一點你將在稍后看到),還可通過使用訪問修飾符對其他包中的類隱藏類成員。要高效地使用包,必須了解幾乎所有JVM項目都遵循的約定。雖然上表選擇的包名完全合法,但給包命名時應遵循一定的約定。2.2.2選擇包名包名必須遵守如下幾個規則。包名可包含句點;實際上,句點用于分隔名稱中的不同元素。包名中的元素可包含字母、數字和下劃線。包名中的每個元素都必須以字母打頭,而不能以數

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論