了解任何一門語言的精髓都是先俯覽其全貌,從宏觀的視角把握全局咱旱,然后再深入每個知識點逐個擊破更鲁,這樣就可以深入而快速的掌握一項技能。同樣學(xué)習(xí) Java 也是如此呵晨,本節(jié)就讓我們先從整體來看一下 Java 中的精髓魏保。
Java 介紹
Java 誕生于 1991 年,Java 的前身叫做 Oak(橡樹)何荚,但在注冊商標(biāo)的時候囱淋,發(fā)現(xiàn)這個名字已經(jīng)被人注冊了,后來團(tuán)隊的人就在咖啡館討論這件事該怎么辦餐塘,有人靈機一動說叫 Java 如何妥衣,因為當(dāng)時他們正在喝著一款叫做 Java 的咖啡。就這樣戒傻,這個后來家喻戶曉的名字税手,竟以這種“隨意”的方式誕生了,并一直沿用至今需纳。
Java 發(fā)展歷程:
1990芦倒,Sun 成立了“Green Team”項目小組
1991,Java 語言前身 Oak(橡樹)誕生
1995不翩,Oak 語言更名為 Java
1996兵扬,Java 1.0 發(fā)布
1997,Java 1.1 發(fā)布
1998口蝠,Java 1.2 發(fā)布
2000器钟,Java 1.3 發(fā)布
2000,Java 1.4 發(fā)布
2004妙蔗,Java 5 發(fā)布
2006傲霸,Java 6 發(fā)布
2011,Java 7 發(fā)布
2014眉反,Java 8 發(fā)布
2017昙啄,Java 9(非長期支持版)發(fā)布
2018.03,Java 10(非長期支持版) 發(fā)布
2018.09寸五,Java 11(長期支持版)發(fā)布
2019.03, Java 12(非長期支持版) 發(fā)布
注:長期支持版指的是官方發(fā)布版本后的一段時間內(nèi)梳凛,通常以“年”為計數(shù)單位,會對此版本進(jìn)行持續(xù)維護(hù)和升級播歼。
版本發(fā)布時間
Java 10 之后伶跷,官方表示每半年推出一個大版本掰读,長期支持版本(LTS)每三年發(fā)布一次。
Java 和 JDK 的關(guān)系
JDK(Java Development Kit)Java 開發(fā)工具包叭莫,它包括:編譯器蹈集、Java 運行環(huán)境(JRE,Java Runtime Environment)雇初、JVM(Java 虛擬機)監(jiān)控和診斷工具等拢肆,而 Java 則表示一種開發(fā)語言。
Java 程序是怎么執(zhí)行的靖诗?
我們?nèi)粘5墓ぷ髦卸际褂瞄_發(fā)工具(IntelliJ IDEA 或 Eclipse 等)可以很方便的調(diào)試程序郭怪,或者是通過打包工具把項目打包成 jar 包或者 war 包,放入 Tomcat 等 Web 容器中就可以正常運行了刊橘,但你有沒有想過 Java 程序內(nèi)部是如何執(zhí)行的鄙才?
其實不論是在開發(fā)工具中運行還是在 Tomcat 中運行,Java 程序的執(zhí)行流程基本都是相同的促绵,它的執(zhí)行流程如下:
先把 Java 代碼編譯成字節(jié)碼攒庵,也就是把 .java 類型的文件編譯成 .class 類型的文件。這個過程的大致執(zhí)行流程:Java 源代碼 -> 詞法分析器 -> 語法分析器 -> 語義分析器 -> 字節(jié)碼生成器 -> 最終生成字節(jié)碼败晴,其中任何一個節(jié)點執(zhí)行失敗就會造成編譯失斉啊;
把 class 文件放置到 Java 虛擬機尖坤,這個虛擬機通常指的是 Oracle 官方自帶的 Hotspot JVM稳懒;
Java 虛擬機使用類加載器(Class Loader)裝載 class 文件;
類加載完成之后慢味,會進(jìn)行字節(jié)碼校驗场梆,字節(jié)碼校驗通過之后 JVM 解釋器會把字節(jié)碼翻譯成機器碼交由操作系統(tǒng)執(zhí)行。但不是所有代碼都是解釋執(zhí)行的纯路,JVM 對此做了優(yōu)化辙谜,比如,以 Hotspot 虛擬機來說感昼,它本身提供了 JIT(Just In Time)也就是我們通常所說的動態(tài)編譯器,它能夠在運行時將熱點代碼編譯為機器碼罐脊,這個時候字節(jié)碼就變成了編譯執(zhí)行定嗓。
Java 程序執(zhí)行流程圖如下:
Java 虛擬機是如何判定熱點代碼的?
Java 虛擬機判定熱點代碼的方式有兩種:
基于采樣的熱點判定
主要是虛擬機會周期性的檢查各個線程的棧頂萍桌,若某個或某些方法經(jīng)常出現(xiàn)在棧頂宵溅,那這個方法就是“熱點方法”。這種判定方式的優(yōu)點是實現(xiàn)簡單上炎;缺點是很難精確一個方法的熱度恃逻,容易受到線程阻塞或外界因素的影響雏搂。
基于計數(shù)器的熱點判定
主要就是虛擬機給每一個方法甚至代碼塊建立了一個計數(shù)器,統(tǒng)計方法的執(zhí)行次數(shù)寇损,超過一定的閥值則標(biāo)記為此方法為熱點方法凸郑。
Hotspot 虛擬機使用的基于計數(shù)器的熱點探測方法。它使用了兩類計數(shù)器:方法調(diào)用計數(shù)器和回邊計數(shù)器矛市,當(dāng)?shù)竭_(dá)一定的閥值是就會觸發(fā) JIT 編譯芙沥。
方法調(diào)用計數(shù)器:在 client 模式下的閥值是 1500 次,Server 是 10000 次浊吏,可以通過虛擬機參數(shù): -XX:CompileThreshold=N 對其進(jìn)行設(shè)置而昨。但是JVM還存在熱度衰減,時間段內(nèi)調(diào)用方法的次數(shù)較少找田,計數(shù)器就減小歌憨。
回邊計數(shù)器:主要統(tǒng)計的是方法中循環(huán)體代碼執(zhí)行的次數(shù)。
由上面的知識我們可以看出墩衙,要想做到對 Java 了如指掌务嫡,必須要好好學(xué)習(xí) Java 虛擬機,那除了 Java 虛擬機外底桂,還有哪些知識是面試必考植袍,也是 Java 工程師必須掌握的知識呢?
1. Java 基礎(chǔ)中的核心內(nèi)容
字符串和字符串常量池的深入理解籽懦、Array 的操作和排序算法于个、深克隆和淺克隆、各種 IO 操作暮顺、反射和動態(tài)代理(JDK 自身動態(tài)代理和 CGLIB)等厅篓。
2. 集合
集合和 String 是編程中最常用的數(shù)據(jù)類型,關(guān)于集合的知識也是面試備考的內(nèi)容捶码,它包含:鏈表(LinkedList)羽氮、TreeSet、棧(Stack)惫恼、隊列(雙端档押、阻塞、非阻塞隊列祈纯、延遲隊列)令宿、HashMap、TreeMap 等腕窥,它們的使用和底層存儲數(shù)據(jù)結(jié)構(gòu)都是熱門的面試內(nèi)容粒没。
3. 多線程
多線程使用和線程安全的知識也是必考的面試題目,它包括:死鎖簇爆、6 種線程池的使用與差異癞松、ThreadLocal爽撒、synchronized、Lock响蓉、JUC(java.util.concurrent包)硕勿、CAS(Compare and Swap)、ABA 問題等厕妖。
4. 熱門框架
Spring首尼、Spring MVC、MyBatis言秸、SpringBoot
5. 分布式編程
消息隊列(RabbitMQ软能、Kafka)、Dubbo举畸、Zookeeper查排、SpringCloud 等。
6. 數(shù)據(jù)庫
MySQL 常用引擎的掌握抄沮、MySQL 前綴索引跋核、回表查詢、數(shù)據(jù)存儲結(jié)構(gòu)叛买、最左匹配原則砂代、MySQL 的問題分析和排除方案、MySQL 讀寫分離的實現(xiàn)原理以及 MySQL 的常見優(yōu)化方案等率挣。 Redis 的使用場景刻伊、緩存雪崩和緩存穿透的解決方案、Redis 過期淘汰策略和主從復(fù)制的實現(xiàn)方案等椒功。
7. Java 虛擬機
虛擬機的組成捶箱、垃圾回收算法动漾、各種垃圾回收器的區(qū)別丁屎、Java 虛擬機分析工具的掌握、垃圾回收器的常用調(diào)優(yōu)參數(shù)等旱眯。
8. 其他
常用算法的掌握音诫、設(shè)計模式的理解竭钝、網(wǎng)絡(luò)知識和常見 Linux 命令的掌握等。
值得慶幸的是以上所有內(nèi)容都包含在本專欄中雹洗,接下來就讓我們一起學(xué)習(xí)香罐,一起構(gòu)建 Java 的認(rèn)知體系吧!
相關(guān)面試題
1. Java 語言都有哪些特點?
答:Java 語言包含以下特點时肿。
面向?qū)ο蟊用#绦蛉菀桌斫狻㈤_發(fā)簡單螃成、方便旦签;
跨平臺,可運行在不同服務(wù)器類型上寸宏,比如:Linux宁炫、Windows、Mac 等氮凝;
執(zhí)行性能好羔巢,運行效率高;
提供大量的 API 擴展覆醇,語言強大朵纷;
有多線程支持,增加了響應(yīng)和實時交互的能力永脓;
安全性好袍辞,自帶驗證機制,確保程序的可靠性和安全性常摧。
2. Java 跨平臺實現(xiàn)的原理是什么搅吁?
答:要了解 Java 跨平臺實現(xiàn)原理之前,必須先要了解 Java 的執(zhí)行過程落午,Java 的執(zhí)行過程如下:
Java 執(zhí)行流程:Java 源代碼(.java)-> 編譯 -> Java 字節(jié)碼(.class) ->通過 JVM(Java 虛擬機)運行 Java 程序谎懦。每種類型的服務(wù)器都會運行一個 JVM,Java 程序只需要生成 JVM 可以執(zhí)行的代碼即可溃斋,JVM 底層屏蔽了不同服務(wù)器類型之間的差異界拦,從而可以在不同類型的服務(wù)器上運行一套 Java 程序。
3. JDK梗劫、JRE享甸、JVM 有哪些區(qū)別截碴?
答:了解了 JDK、JRE蛉威、JVM 的定義也就明白了它們之間的區(qū)別日丹,如下所述。
JDK:Java Development Kit(Java 開發(fā)工具包)的簡稱蚯嫌,提供了 Java 的開發(fā)環(huán)境和運行環(huán)境哲虾;
JRE:Java Runtime Environment(Java 運行環(huán)境)的簡稱,為 Java 的運行提供了所需環(huán)境择示;
JVM:Java Virtual Machine(Java虛擬機)的簡稱束凑,是一種用于計算設(shè)備的規(guī)范,它是一個虛構(gòu)出來的計算機对妄,是通過在實際的計算機上仿真模擬各種計算機功能來實現(xiàn)的湘今,簡單來說就是所有的 Java 程序都是運行在 JVM(Java 虛擬機)上的。
總體來說剪菱,JDK 提供了一整套的 Java 運行和開發(fā)環(huán)境摩瞎,通常使用對象為 Java 的開發(fā)者,當(dāng)然 JDK 也包含了 JRE孝常;而 JRE 為 Java 運行的最小運行單元旗们,一般安裝在 Java 服務(wù)器上,所以 JDK 和 JRE 可以從用途上進(jìn)行理解和區(qū)分构灸。JVM 不同于 JDK 和 JRE上渴,JVM 是 Java 程序運行的載體,Java 程序只有通過 JVM 才能正常的運行喜颁。
4. Java 中如何獲取明天此刻的時間稠氮?
答:JDK 8 之前使用 Calendar.add() 方法獲取,代碼如下:
Calendarcalendar=Calendar.getInstance();
calendar.add(Calendar.DATE,1);
System.out.println(calendar.getTime());
JDK 8 有兩種獲取明天時間的方法半开。
方法一隔披,使用 LocalDateTime.plusDays() 方法獲取,代碼如下:
LocalDateTimetoday=LocalDateTime.now();
LocalDateTimetomorrow=today.plusDays(1);
System.out.println(tomorrow);
方法二寂拆,使用 LocalDateTime.minusDays() 方法獲取奢米,代碼如下:
LocalDateTimetoday=LocalDateTime.now();
LocalDateTimetomorrow=today.minusDays(-1);
System.out.println(tomorrow);
minusDays() 方法為當(dāng)前時間減去 n 天,傳負(fù)值就相當(dāng)于當(dāng)前時間加 n 天纠永。
5. Java 中如何跳出多重嵌套循環(huán)鬓长?
答:Java 中跳出多重嵌套循環(huán)的兩種方式。
方法一:定義一個標(biāo)號尝江,使用 break 加標(biāo)號的方式
方法二:使用全局變量終止循環(huán)
方法一涉波,示例代碼:
myfor:for(inti=0;i<100;i++) {
for(intj=0;j<100;j++) {
System.out.println("J:"+j);
if(j==10) {
// 跳出多重循環(huán)
breakmyfor;
? ? ?? }
?? }
}
方法二,示例代碼:
booleanflag=true;
for(inti=0;i<100&&flag;i++) {
for(intj=0;j<100;j++) {
System.out.println("J:"+j);
if(j==10) {
// 跳出多重循環(huán)
flag=false;
break;
? ? ?? }
?? }
}
6. char 變量能不能存貯一個中文漢字?為什么啤覆?
答:char 變量可以存貯一個漢字善延,因為 Java 中使用的默認(rèn)編碼是 Unicode ,一個 char 類型占 2 個字節(jié)(16 bit)城侧,所以放一個中文是沒問題的。
7. Java 中會存在內(nèi)存泄漏嗎彼妻?請簡單描述一下嫌佑。
答:一個不再被程序使用的對象或變量一直被占據(jù)在內(nèi)存中就造成了內(nèi)存泄漏。
Java 中的內(nèi)存泄漏的常見情景如下:
長生命周期對象持有短生命的引用侨歉,比如屋摇,緩存系統(tǒng),我們加載了一個對象放在緩存中幽邓,然后一直不使用這個緩存炮温,由于緩存的對象一直被緩存引用得不到釋放,就造成了內(nèi)存泄漏牵舵;
各種連接未調(diào)用關(guān)閉方法柒啤,比如,數(shù)據(jù)庫 Connection 連接畸颅,未顯性地關(guān)閉担巩,就會造成內(nèi)存泄漏;
內(nèi)部類持有外部類没炒,如果一個外部類的實例對象的方法返回了一個內(nèi)部類的實例對象涛癌,這個內(nèi)部類對象被長期引用了,即使那個外部類實例對象不再被使用送火,但由于內(nèi)部類持有外部類的實例對象拳话,這個外部類對象將不會被垃圾回收,這也會造成內(nèi)存泄露种吸;
改變哈希值弃衍,當(dāng)一個對象被存儲進(jìn) HashSet 集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了骨稿,否則對象修改后的哈希值與最初存儲進(jìn) HashSet 集合中時的哈希值就不同了笨鸡,在這種情況下,即使在 contains 方法使用該對象的當(dāng)前引用作為的參數(shù)去 HashSet 集合中檢索對象坦冠,也將返回找不到對象的結(jié)果形耗,這也會導(dǎo)致無法從 HashSet 集合中單獨刪除當(dāng)前對象,造成內(nèi)存泄露辙浑。