
概述
在過去的20年里,如果要選一個最成功的編程語言那一定非Java莫屬。根據(jù)TIOBE Index發(fā)布的編程語言排行榜,自2001年以來Java語言在這個排行榜上最差的名次是第二名。在20年的發(fā)展歷程中,Java已經(jīng)不僅僅是一門編程語言,它更是一個平臺,是一系列的計算機(jī)軟件和規(guī)范形成的技術(shù)體系,從嵌入式系統(tǒng)、移動終端到個人計算機(jī)、服務(wù)器等領(lǐng)域,Java都占據(jù)著舉足輕重的位置。按照官方網(wǎng)站在2016年提供的數(shù)據(jù),全球有900萬Java開發(fā)人員并有約60億臺設(shè)備都在運(yùn)行Java程序,這些數(shù)字都是非常震撼的。
術(shù)語
想了解Java,有三個術(shù)語必須要知道:
JDK:Java開發(fā)者工具 - Java Developer's Kit
JRE:Java運(yùn)行時環(huán)境 - Java Runtime Environment
JVM:Java虛擬機(jī) - Java Virtual Machine
歷史
關(guān)于Java這20年的故事,不是一兩句話能說清楚的,下面用編年史的方式做一個簡要的介紹。
- 1991年4月,James Gosling(計算機(jī)界的全能奇才,被稱為“Java之父”)領(lǐng)導(dǎo)的Green Project啟動,雖然項目項目并不成功,但是在項目中誕生的Oak語言伴隨著互聯(lián)網(wǎng)潮流的興起,迅速找到了適合自己發(fā)展的市場定位并最終蛻變?yōu)镴ava語言。
- 1995年5月23日,Java誕生。
- 1996年1月23日,JDK 1.0正式發(fā)布。
- 1996年5月,第一屆JavaOne大會在舊金山舉行。
- 1997年2月19日, SUN公司發(fā)布JDK 1.1,代表性的技術(shù)包括:JAR文件格式、JDBC、JavaBeans、RMI、內(nèi)部類和反射等。
- 1998年12月4日,JDK迎來了里程碑式的版本JDK 1.2,SUN公司將Java技術(shù)拆分為3個方向,分別是面向桌面應(yīng)用開發(fā)的J2SE、面向企業(yè)級開發(fā)的J2EE和面向移動終端開發(fā)的J2ME。該版本首次在Java虛擬機(jī)中內(nèi)置了JIT編譯器。
- 2000年5月8日,JDK 1.3發(fā)布,代號Kestrel,改進(jìn)了數(shù)學(xué)運(yùn)算、時間以及Java 2D等API,新增了和聲音處理相關(guān)的類庫。此后,SUN公司基本每個兩年發(fā)布一個JDK的主版本,產(chǎn)品代號都以動物命名。
- 2002年2月13日,JDK 1.4發(fā)布,代號Merlin,Java開始走向成熟并逐漸達(dá)到巔峰,今天很多主流框架仍然可以在JDK 1.4上直接運(yùn)行。該版本中引入了正則表達(dá)式、異常鏈、NIO、日志類、XML解析器等。
- 2004年9月30日,JDK 1.5發(fā)布,代號Tiger,該版本在Java語法的易用性上做出了很大的改進(jìn),引入了自動裝箱、泛型、注解、枚舉、可變參數(shù)列表、for-each循環(huán)等特性,同時在這個版本中還對Java內(nèi)存模型進(jìn)行了改進(jìn),同時引入了更優(yōu)質(zhì)的用于多線程編程的java.util.concurrent包。
- 2006年12月11日,JDK 1.6發(fā)布,代號Mustang,在這個版本中,J2SE、J2EE和J2ME被更名為Java SE、Java EE和Java ME,提供了對腳本語言的支持以及編譯器API和微型HTTP服務(wù)器API等內(nèi)容。此外,該版本還對Java虛擬機(jī)內(nèi)部進(jìn)行了大量的優(yōu)化,包括垃圾回收、類加載、鎖機(jī)制等。同年,SUN公司開始逐漸陷入困境。
- 2009年2月19日,JDK 1.7發(fā)布,代號Dolphin,JDK 1.7最初計劃引入很多開發(fā)者翹首以盼的功能,包括Lambda表達(dá)式,Jigsaw項目、動態(tài)語言支持、G1收集器和Coin項目,但是如前所述,由于SUN公司已經(jīng)陷入困境,無力推動研發(fā)工作按正常計劃進(jìn)行,在4月20日Oracle公司宣布以74億美元收購SUN公司,Java商標(biāo)從此歸Oracle所有,此后Oracle公司執(zhí)行了所謂的“B計劃”,大幅裁剪了JDK 1.7的預(yù)定目標(biāo),把諸多內(nèi)容推遲到了JDK 1.8中,隨后又宣布Jigsaw在JDK 1.8中依然無法完成。
- 2014年3月18日,在漫長的等待后,“跳票王”O(jiān)racle公司終于推出了JDK 1.8,沒有產(chǎn)品代號,這一次真可以說得上是“千呼萬喚始出來”。
特點(diǎn)
自Java誕生以來,你可能聽過很多關(guān)于Java有多么牛逼的描述,但是其中很多內(nèi)容都是過去時,當(dāng)下的Java最吸引人的地方應(yīng)該在于以下幾個方面。
- 對函數(shù)式編程的支持:面向?qū)ο蟮木幊趟枷胱寫?yīng)用程序的開發(fā)變得簡單輕松,通過給對象發(fā)送消息很多問題就可以得到解決;而函數(shù)式編程的思想則源于λ 演算,強(qiáng)調(diào)使用表達(dá)式而不是語句,通過不改變狀態(tài)的操作讓代碼沒有副作用,這些都迎合了很多領(lǐng)域的開發(fā)者的需求,當(dāng)下很多高級編程語言都提供了對函數(shù)式編程的支持,Java終于在JDK 1.8中引入了Lambda表達(dá)式、函數(shù)式接口、方法引用等高級語法來支持函數(shù)式編程,且看一小段代碼。
import java.util.List;
import java.util.Arrays;
class Hello {
public static void main(String[] args) {
List<String> list = Arrays.asList("apple", "grape", "pitaya");
list.forEach(System.out::println);
}
}
- 始終如一的平臺可移植性:平臺可移植性從來都是Java最大的賣點(diǎn),通過在不同的平臺下安裝對應(yīng)的JVM來加載類文件執(zhí)行,雖然在一定程度上犧牲了執(zhí)行效率,但獲得的是完美的平臺可移植性。
- 支持多種編程語言混編:目前的JVM已經(jīng)能夠支持諸如Groovy、Scala、Clojure這樣的語言進(jìn)行開發(fā)。使用非Java語言主要是出于這些考慮:首先使用領(lǐng)域特定語言可以方便構(gòu)建、持續(xù)集成、業(yè)務(wù)規(guī)則建模等操作;其次也可以利用一些動態(tài)語言的特性來彌補(bǔ)Java本身的不足,滿足快速Web開發(fā)、腳本編程和測試等方面的需求。今天有很多軟件和系統(tǒng)的開發(fā)都是通過多語言混編實現(xiàn)的。
- 對多核并發(fā)編程的支持:Java語言內(nèi)置的對多線程編程的支持是Java早期的一大賣點(diǎn),但在今天看來已經(jīng)不是什么了不起的事情。隨著CPU進(jìn)入多核時代,Java在并發(fā)編程上也做出了與時俱進(jìn)的升級,從JDK 1.5的java.util.concurrent包,到JDK 1.7引入Fork/Join模式,Java程序已經(jīng)能夠輕松的利用多個CPU核心提供的計算能力來協(xié)作完成更復(fù)雜的任務(wù)。
探秘
想要深入學(xué)習(xí)和了解Java,可以對JVM進(jìn)行一次探秘。
JVM中的內(nèi)存
- 程序計數(shù)器(Program Counter Register)
程序計數(shù)器可以視為當(dāng)前線程所執(zhí)行的字節(jié)碼的行號指示器,字節(jié)碼解釋器工作時就是通過改變程序計數(shù)器的值來選取下一條需要執(zhí)行的字節(jié)碼指令。對于多線程的應(yīng)用程序,每個線程都需要有一個獨(dú)立的程序計數(shù)器,線程之間互不影響,因此程序計數(shù)器是線程私有的內(nèi)存。 - 虛擬機(jī)棧(VM Stack)
Java虛擬機(jī)棧也是線程私有的,它描述了Java方法執(zhí)行的內(nèi)存模型,即每個方法在執(zhí)行時都會創(chuàng)建一個棧幀用于存儲局部變量表(存放了編譯期可知的基本數(shù)據(jù)類型,包括:byte、short、int、long、float、double、char、boolean,對象的引用以及返回地址)、操作數(shù)棧、動態(tài)鏈接、方法出口等信息。在JVM規(guī)范中,對這個區(qū)域規(guī)定了兩種異常狀況:如果線程請求的棧深度大于虛擬機(jī)所允許的深度,將引發(fā)StackOverflowError;如果虛擬機(jī)棧需要擴(kuò)展空間但無法申請到足夠的內(nèi)存,將引發(fā)OutOfMemoryError。 - 本地方法棧(Native Method Stack)
本地方法棧顧名思義是調(diào)用本地方法(用C/C++編寫的方法)時使用的棧。 -
堆(Heap)
堆是JVM所管理的內(nèi)存中最大的一塊,它是被所有線程共享的內(nèi)存區(qū)域,在JVM啟動時創(chuàng)建,用于存放對象實例。在JVM規(guī)范中明確指出:The heap is the runtime data area from which memory for all class instances and arrays is allocated. 但是隨著JIT編譯器的發(fā)展與逃逸分析技術(shù)的逐漸成熟,對象實例的棧上分配、標(biāo)量替換優(yōu)化將使得“對象一定在堆上”這個說法變得不那么絕對了。堆是Java垃圾收集器管理的主要區(qū)域,現(xiàn)在的垃圾收集器都基于分代收集算法,堆通常分為新生代和老生代,新生代具體又可細(xì)分為Eden、From Survivor和To Survivor。在啟動JVM時可以通過-Xmx和-Xms來控制堆的大小,還可以通過-Xmn和-XX:NewRatio來控制新生代的大小以及新生代和老生代的比例,如果想了解垃圾收集器的工作細(xì)節(jié),可以使用-XX:+PrintGCDetails來做到。
- 方法區(qū)(Method Area)
方法區(qū)也是線程共享的內(nèi)存區(qū)域,用于存儲已被JVM加載的類的信息、常量、靜態(tài)變量、JIT編譯后的代碼等數(shù)據(jù)。方法區(qū)中比較重要的一塊是運(yùn)行時常量池(Constant Pool),它允許運(yùn)行期間將新的常量放入池中,String類的intern()方法就是一個例子。當(dāng)常量池?zé)o法再申請到內(nèi)存時也會引發(fā)OutOfMemoryError。 - 直接內(nèi)存
JDK1.4中引入了NIO(非阻塞式I/O),它可以使用本地方法分配堆以外的內(nèi)存,然后通過ByteBuffer/CharBuffer對象來操作這些內(nèi)存,從而實現(xiàn)提升性能的目標(biāo)。
說明:Java虛擬機(jī)是非常復(fù)雜的,如果想要真正理解它的工作原理,可以嘗試自己寫一個Java虛擬機(jī)。不要覺得這件事情遙不可及,有一本名為《自己動手寫Java虛擬機(jī)》的書就用Go語言實現(xiàn)了一個自己的JVM。
JVM中的對象
- 對象的創(chuàng)建
虛擬機(jī)遇到一條new指令時,首先將檢查這個指令對應(yīng)的參數(shù)是不是能在常量池中定位到的一個類的符號引用,然后還要檢查這個對應(yīng)的類是否已經(jīng)被加載、解析和初始化過,如果沒有就要執(zhí)行類加載(具體的細(xì)節(jié)將在后續(xù)的文章中探討)。接下來需要為對象分配內(nèi)存空間,而且內(nèi)存空間除對象頭外都要被初始化為0值,這就保證了對象的屬性在不賦初始值的情況下就能直接使用。再下來,JVM要對對象進(jìn)行必要的設(shè)置,主要是對象頭的設(shè)置以及對象的初始化工作(按照程序員的意愿為屬性設(shè)定對應(yīng)的值),到此一個對象就真正的完成了創(chuàng)建過程。 - 對象的內(nèi)存布局
對于HotSpot虛擬機(jī)而言,對象在內(nèi)存中的布局可以為分3塊區(qū)域:對象頭、實力數(shù)據(jù)和對齊填充。對象頭包含兩部分信息,第一部分用于存儲對象自身的運(yùn)行時數(shù)據(jù),如哈希碼、GC分代年齡、鎖狀態(tài)標(biāo)識等;另一部分是類型指針,也就是對象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過這個指針來確定這個對象是哪個類的實例。 - 對象的訪問定位
訪問一個對象基本上有兩種策略:一種是通過句柄訪問,引用中存儲的是句柄地址,這種方式首先需要在Java堆中劃分一塊內(nèi)存作為句柄池,當(dāng)對象指針發(fā)生改變(比如對象被移動),這個時候引用本身的值不需要改變,改變的只是句柄的值;另一種是直接指針訪問,引用直接指向內(nèi)存堆空間中對象的地址。由于對象訪問在JVM中非常的頻繁,所以第一種方法會造成較大的開銷,因此HotSpot虛擬機(jī)采用了第二種方式。
開發(fā)
如果只想運(yùn)行Java程序,那么有JRE就足夠了,因為它包含了運(yùn)行Java程序所需的虛擬機(jī)還有就是支撐程序運(yùn)行的上下文環(huán)境;如果想要用Java開發(fā)應(yīng)用程序那么就得有JDK,因為JDK中包含了Java開發(fā)的必要工具。當(dāng)然,在開發(fā)過程中使用IDE(集成開發(fā)環(huán)境)可以大大提升開發(fā)效率。對于Java開發(fā)而言,可以選擇的IDE主要有三個:
-
Eclipse:國內(nèi)有很多程序員都在使用Eclipse,因為它簡單、免費(fèi)、還有很多提升開發(fā)效率的特性。
-
IntelliJ:集成的插件和功能較多,代碼提示和修復(fù)能力強(qiáng)大,可以根據(jù)需求對IDE進(jìn)行定制,有免費(fèi)和付費(fèi)兩種版本,后者支持的功能更多更強(qiáng)大。
- NetBeans:我自己使用這個IDE的次數(shù)非常少,因此也只能說這是官方提供的開發(fā)工具。
書籍
- 入門讀物:Core Java(中文名:《Java核心技術(shù)》,目前最新的版本是第10版,非常棒的入門書?。?/li>
- 進(jìn)階讀物:Thinking in Java(中文名:《Java編程思想》)、Effective Java(提升Java水平必讀書籍)、Refactor(中文名《重構(gòu):改善既有代碼設(shè)計》,編程大師Martin Fowler神作)、《Java與模式》(美籍華人閻宏博士力作)


