Java是什麼
Java是一種高階的物件導向的程式設計語言 。
Java的特性
- 物件導向(封裝,繼承,多型)
- 平臺無關性(JVM執行.class檔案)
- 語言(泛型,Lambda)
- 類庫(集合,併發,網路,IO/NIO)
- JRE(Java執行環境,JVM,類庫)
- JDK(Java開發工具,包括JRE,javac,診斷工具)
Java是解釋執行,這句話正確嗎?
Java本身是一種物件導向的語言,最顯著的特性有兩個方面,一是所謂的“一次編譯,到處執行”(Compile once, run anywhere),能夠非常容易地獲得跨平臺能力;另外就是垃圾收集(GC, Garbage Collection),Java通過垃圾收集器(Garbage Collector)回收分配記憶體,大部分情況下,程式設計師不需要自己操心記憶體的分配和回收。
一次編譯、到處執行”說的是Java語言跨平臺的特性,Java的跨平臺特性與Java虛擬機器的存在密不可分,可在不同的環境中執行。比如說Windows平臺和Linux平臺都有相應的JDK,安裝好JDK後也就有了Java語言的執行環境。其實Java語言本身與其他的程式語言沒有特別大的差異,並不是說Java語言可以跨平臺,而是在不同的平臺都有可以讓Java語言執行的環境而已,所以才有了Java一次編譯,到處執行這樣的效果。 嚴格的講,跨平臺的語言不止Java一種,但Java是較為成熟的一種。“一次編譯,到處執行”這種效果跟編譯器有關。程式語言的處理需要編譯器和直譯器。Java虛擬機器和DOS類似,相當於一個供程式執行的平臺。 程式從原始碼到執行的三個階段:編碼——編譯——執行——除錯。Java在編譯階段則體現了跨平臺的特點。編譯過程大概是這樣的:首先是將Java原始碼轉化成.CLASS檔案位元組碼,這是第一次編譯。.class檔案就是可以到處執行的檔案。然後Java位元組碼會被轉化為目標機器程式碼,這是是由JVM來執行的,即Java的第二次編譯。 “到處執行”的關鍵和前提就是JVM。因為在第二次編譯中JVM起著關鍵作用。在可以執行Java虛擬機器的地方都內含著一個JVM作業系統。從而使JAVA提供了各種不同平臺上的虛擬機器制,因此實現了“到處執行”的效果。需要強調的一點是,java並不是編譯機制,而是解釋機制。Java位元組碼的設計充分考慮了JIT這一即時編譯方式,可以將位元組碼直接轉化成高效能的本地機器碼,這同樣是虛擬機器的一個構成部分。
我們日常會接觸到 JRE(Java Runtime Environment)或者 JDK(Java Development Kit)。 JRE,也就是 Java執行環境,包含了 JVM和 Java類庫,以及一些模組等。而 JDK可以看作是 JRE的一個超集,提供了更多工具,比如編譯器、各種診斷工具等。 對於“Java是解釋執行”這句話,這個說法不太準確。我們開發的 Java的原始碼,首先通過 Javac編譯成為位元組碼(bytecode),然後,在執行時,通過 Java虛擬機器(JVM)內嵌的直譯器將位元組碼轉換成為最終的機器碼。但是常見的 JVM,比如我們大多數情況使用的 Oracle JDK提供的 Hospot JVM,都提供了 JIT(Just-In-Time)編譯器,也就是通常所說的動態編譯器,JIT能夠在執行時將熱點程式碼編譯成機器碼,這種情況下部分熱點程式碼就屬於編譯執行,而不是解釋執行了。
JVM(Java Virtual Machine)
-
什麼是JVM?
(JVM)Java Virtual Machine,是Java程式跨平臺的關鍵,不同的平臺有不同的JVM,而java位元組碼不包含任何與平臺相關的資訊,不直接與平臺互動,而是通過JVM間接與平臺互動。應用程式在執行時,JVM載入位元組碼,將位元組碼解釋成特定平臺的機器碼,讓平臺執行。眾所周知,我們通常把 Java分為編譯期和執行時。這裡說的 Java的編譯和 C/C++是有著不同的意義的,Javac的編譯,編譯 Java原始碼生成“.class”檔案裡面實際是位元組碼,而不是可以直接執行的機器碼。Java通過位元組碼和 Java虛擬機器(JVM)這種跨平臺的抽象,遮蔽了作業系統和硬體的細節,這也是實現“一次編譯,到處執行”的基礎。
-
類載入
在執行時,JVM 會通過類載入器(Class-Loader)載入位元組碼,解釋或者編譯執行。就像我前面提到的,主流 Java 版本中,如 JDK 8 實際是解釋和編譯混合的一種模式,即所謂的混合模式(-Xmixed)。通常執行在 server 模式的 JVM,會進行上萬次呼叫以收集足夠的資訊進行高效的編譯,client 模式這個門限是 1500 次。Oracle Hotspot JVM 內建了兩個不同的 JIT compiler,C1 對應前面說的 client 模式,適用於對於啟動速度敏感的應用,比如普通 Java 桌面應用;C2 對應 server 模式,它的優化是為長時間執行的伺服器端應用設計的。預設是採用所謂的分層編譯(TieredCompilation)。這裡不再展開更多 JIT 的細節,沒必要一下子就鑽進去。
除了我們日常最常見的 Java使用模式,其實還有一種新的編譯方式,即所謂的 AOT(Ahead-of-Time Compilation),直接將位元組碼編譯成機器程式碼,這樣就避免了 JIT預熱等各方面的開銷,比如 Oracle JDK 9就引入了實驗性的 AOT特性,並且增加了新的 jaotc工具。利用下面的命令把某個類或者某個模組編譯成為 AOT庫。
jaotc --output libHelloWorld.so HelloWorld.class
jaotc --output libjava.base.so --module java.base
複製程式碼
然後,在啟動時直接指定就可以了。
java -XX:AOTLibrary=./libHelloWorld.so,./libjava.base.so HelloWorld
複製程式碼
而且,Oracle JDK支援分層編譯和 AOT協作使用,這兩者並不是二選一的關係。如果你有興趣,可以參考相關文件:openjdk.java.net/jeps/295。AOT也不僅僅是隻有這一種方式,業界早就有第三方工具(如 GCJ、Excelsior JET)提供相關功能。
另外,JVM作為一個強大的平臺,不僅僅只有 Java語言可以執行在 JVM上,本質上合規的位元組碼都可以執行,Java語言自身也為此提供了便利,我們可以看到類似 Clojure、Scala、Groovy、JRuby、Jython等大量 JVM語言,活躍在不同的場景。
擴充套件
對於 Java 平臺的理解,可以從很多方面簡明扼要地談一下,例如:Java 語言特性,包括泛型、Lambda 等語言特性;基礎類庫,包括集合、IO/NIO、網路、併發、安全等基礎類庫。對於我們日常工作應用較多的類庫,面試前可以系統化總結一下,有助於臨場發揮。
或者談談 JVM 的一些基礎概念和機制,比如 Java 的類載入機制,常用版本 JDK(如 JDK 8)內嵌的 Class-Loader,例如 Bootstrap、 Application 和 Extension Class-loader;類載入大致過程:載入、驗證、連結、初始化(這裡參考了周志明的《深入理解 Java 虛擬機器》,非常棒的 JVM 上手書籍);自定義 Class-Loader 等。還有垃圾收集的基本原理,最常見的垃圾收集器,如 SerialGC、Parallel GC、 CMS、 G1 等,對於適用於什麼樣的工作負載最好也心裡有數。這些都是可以擴充套件開的領域,我會在後面的專欄對此進行更系統的介紹。
當然還有 JDK 包含哪些工具或者 Java 領域內其他工具等,如編譯器、執行時環境、安全工具、診斷和監控工具等。這些基本工具是日常工作效率的保證,對於我們工作在其他語言平臺上,同樣有所幫助,很多都是觸類旁通的。
下圖是總結的一個相對寬泛的藍圖供大家參考
補充!
微觀角度: Java平臺中有兩大核心:
- Java語言本身、JDK中所提供的核心類庫和相關工具
- Java虛擬機器以及其他包含的GC
Java語言本身、JDK中所提供的核心類庫和相關工具 從事Java平臺的開發,掌握Java語言、核心類庫以及相關工具是必須的,我覺得這是基礎中的基礎。 對語言本身的瞭解,需要開發者非常熟悉語言的語法結構;而Java又是一種面對物件的語言,這又需要開發者深入瞭解面對物件的設計理念; Java核心類庫包含集合類、執行緒相關類、IO、NIO、J.U.C併發包等; JDK提供的工具包含:基本的編譯工具、虛擬機器效能檢測相關工具等。
- 大部分情況下,程式設計者只需要關心Java語言本身,而無需特意關心底層細節。包括對記憶體的分配和回收,也全權交給了GC。
- 對於虛擬機器而言,只要是符合規範的位元組碼,它們都能被載入執行,當然,能正常執行的程式光滿足這點是不行的,程式本身需要保證在執行時不出現異常。所以,Scala、Kotlin、Jython等語言也可以跑在虛擬機器上。
本文總結出自極客時間的『Java核心技術36講』