第 1-1 课:Java 程序是如何执行的?
了解任何一門語(yǔ)言的精髓都是先俯覽其全貌,從宏觀的視角把握全局,然后再深入每個(gè)知識(shí)點(diǎn)逐個(gè)擊破,這樣就可以深入而快速的掌握一項(xiàng)技能。同樣學(xué)習(xí) Java 也是如此,本節(jié)就讓我們先從整體來(lái)看一下 Java 中的精髓。
Java 介紹
Java 誕生于 1991 年,Java 的前身叫做 Oak(橡樹),但在注冊(cè)商標(biāo)的時(shí)候,發(fā)現(xiàn)這個(gè)名字已經(jīng)被人注冊(cè)了,后來(lái)團(tuán)隊(duì)的人就在咖啡館討論這件事該怎么辦,有人靈機(jī)一動(dòng)說(shuō)叫 Java 如何,因?yàn)楫?dāng)時(shí)他們正在喝著一款叫做 Java 的咖啡。就這樣,這個(gè)后來(lái)家喻戶曉的名字,竟以這種“隨意”的方式誕生了,并一直沿用至今。
Java 發(fā)展歷程:
- 1990,Sun 成立了“Green Team”項(xiàng)目小組
- 1991,Java 語(yǔ)言前身 Oak(橡樹)誕生
- 1995,Oak 語(yǔ)言更名為 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(非長(zhǎng)期支持版)發(fā)布
- 2018.03,Java 10(非長(zhǎng)期支持版) 發(fā)布
- 2018.09,Java 11(長(zhǎng)期支持版)發(fā)布
- 2019.03, Java 12(非長(zhǎng)期支持版) 發(fā)布
注:長(zhǎng)期支持版指的是官方發(fā)布版本后的一段時(shí)間內(nèi),通常以“年”為計(jì)數(shù)單位,會(huì)對(duì)此版本進(jìn)行持續(xù)維護(hù)和升級(jí)。
版本發(fā)布時(shí)間 Java 10 之后,官方表示每半年推出一個(gè)大版本,長(zhǎng)期支持版本(LTS)每三年發(fā)布一次。
Java 和 JDK 的關(guān)系
JDK(Java Development Kit)Java 開發(fā)工具包,它包括:編譯器、Java 運(yùn)行環(huán)境(JRE,Java Runtime Environment)、JVM(Java 虛擬機(jī))監(jiān)控和診斷工具等,而 Java 則表示一種開發(fā)語(yǔ)言。
Java 程序是怎么執(zhí)行的?
我們?nèi)粘5墓ぷ髦卸际褂瞄_發(fā)工具(IntelliJ IDEA 或 Eclipse 等)可以很方便的調(diào)試程序,或者是通過(guò)打包工具把項(xiàng)目打包成 jar 包或者 war 包,放入 Tomcat 等 Web 容器中就可以正常運(yùn)行了,但你有沒(méi)有想過(guò) Java 程序內(nèi)部是如何執(zhí)行的?
其實(shí)不論是在開發(fā)工具中運(yùn)行還是在 Tomcat 中運(yùn)行,Java 程序的執(zhí)行流程基本都是相同的,它的執(zhí)行流程如下:
Java 程序執(zhí)行流程圖如下:
Java 虛擬機(jī)是如何判定熱點(diǎn)代碼的?
Java 虛擬機(jī)判定熱點(diǎn)代碼的方式有兩種:
- 基于采樣的熱點(diǎn)判定
主要是虛擬機(jī)會(huì)周期性的檢查各個(gè)線程的棧頂,若某個(gè)或某些方法經(jīng)常出現(xiàn)在棧頂,那這個(gè)方法就是“熱點(diǎn)方法”。這種判定方式的優(yōu)點(diǎn)是實(shí)現(xiàn)簡(jiǎn)單;缺點(diǎn)是很難精確一個(gè)方法的熱度,容易受到線程阻塞或外界因素的影響。
- 基于計(jì)數(shù)器的熱點(diǎn)判定
主要就是虛擬機(jī)給每一個(gè)方法甚至代碼塊建立了一個(gè)計(jì)數(shù)器,統(tǒng)計(jì)方法的執(zhí)行次數(shù),超過(guò)一定的閥值則標(biāo)記為此方法為熱點(diǎn)方法。
Hotspot 虛擬機(jī)使用的基于計(jì)數(shù)器的熱點(diǎn)探測(cè)方法。它使用了兩類計(jì)數(shù)器:方法調(diào)用計(jì)數(shù)器和回邊計(jì)數(shù)器,當(dāng)?shù)竭_(dá)一定的閥值是就會(huì)觸發(fā) JIT 編譯。
方法調(diào)用計(jì)數(shù)器:在 client 模式下的閥值是 1500 次,Server 是 10000 次,可以通過(guò)虛擬機(jī)參數(shù): -XX:CompileThreshold=N 對(duì)其進(jìn)行設(shè)置。但是JVM還存在熱度衰減,時(shí)間段內(nèi)調(diào)用方法的次數(shù)較少,計(jì)數(shù)器就減小。
回邊計(jì)數(shù)器:主要統(tǒng)計(jì)的是方法中循環(huán)體代碼執(zhí)行的次數(shù)。
由上面的知識(shí)我們可以看出,要想做到對(duì) Java 了如之中,必須要好好學(xué)習(xí) Java 虛擬機(jī),那除了 Java 虛擬機(jī)外,還有哪些知識(shí)是面試必考,也是 Java 工程師必須掌握的知識(shí)呢?
1. Java 基礎(chǔ)中的核心內(nèi)容
字符串和字符串常量池的深入理解、Array 的操作和排序算法、深克隆和淺克隆、各種 IO 操作、反射和動(dòng)態(tài)代理(JDK 自身動(dòng)態(tài)代理和 CGLIB)等。
2. 集合
集合和 String 是編程中最常用的數(shù)據(jù)類型,關(guān)于集合的知識(shí)也是面試備考的內(nèi)容,它包含:鏈表(LinkedList)、TreeSet、棧(Stack)、隊(duì)列(雙端、阻塞、非阻塞隊(duì)列、延遲隊(duì)列)、HashMap、TreeMap 等,它們的使用和底層存儲(chǔ)數(shù)據(jù)結(jié)構(gòu)都是熱門的面試內(nèi)容。
3. 多線程
多線程使用和線程安全的知識(shí)也是必考的面試題目,它包括:死鎖、6 種線程池的使用與差異、ThreadLocal、synchronized、Lock、JUC(java.util.concurrent包)、CAS(Compare and Swap)、ABA 問(wèn)題等。
4. 熱門框架
Spring、Spring MVC、MyBatis、SpringBoot
5. 分布式編程
消息隊(duì)列(RabbitMQ、Kafka)、Double、Zookeeper、SpringCloud 等。
6. 數(shù)據(jù)庫(kù)
MySQL、Redis
7. Java 虛擬機(jī)
虛擬機(jī)的組成、垃圾回收算法、各種垃圾回收器、Java 虛擬機(jī)分析工具、Java 虛擬機(jī)常用調(diào)優(yōu)配置等。
8. 其他
常用算法、設(shè)計(jì)模式
值得慶幸的是以上所有內(nèi)容都包含在本課程中,接下來(lái)就讓我們一起學(xué)習(xí),一起構(gòu)建 Java 的認(rèn)知體系吧。
相關(guān)面試題
1. Java 語(yǔ)言都有哪些特點(diǎn)?
答:Java 語(yǔ)言包含以下特點(diǎn)。
- 面向?qū)ο?#xff0c;程序容易理解、開發(fā)簡(jiǎn)單、方便;
- 跨平臺(tái),可運(yùn)行在不同服務(wù)器類型上,比如:Linux、Windows、Mac 等;
- 執(zhí)行性能好,運(yùn)行效率高;
- 提供大量的 API 擴(kuò)展,語(yǔ)言強(qiáng)大;
- 有多線程支持,增加了響應(yīng)和實(shí)時(shí)交互的能力;
- 安全性好,自帶驗(yàn)證機(jī)制,確保程序的可靠性和安全性。
2. Java 跨平臺(tái)實(shí)現(xiàn)的原理是什么?
答:要了解 Java 跨平臺(tái)實(shí)現(xiàn)原理之前,必須先要了解 Java 的執(zhí)行過(guò)程,Java 的執(zhí)行過(guò)程如下:
Java 執(zhí)行流程:Java 源代碼(.java)-> 編譯 -> Java 字節(jié)碼(.class) ->通過(guò) JVM(Java 虛擬機(jī))運(yùn)行 Java 程序。每種類型的服務(wù)器都會(huì)運(yùn)行一個(gè) JVM,Java 程序只需要生成 JVM 可以執(zhí)行的代碼即可,JVM 底層屏蔽了不同服務(wù)器類型之間的差異,從而可以在不同類型的服務(wù)器上運(yùn)行一套 Java 程序。
3. JDK、JRE、JVM 有哪些區(qū)別?
答:了解了 JDK、JRE、JVM 的定義也就明白了它們之間的區(qū)別,如下所述。
- JDK:Java Development Kit(Java 開發(fā)工具包)的簡(jiǎn)稱,提供了 Java 的開發(fā)環(huán)境和運(yùn)行環(huán)境;
- JRE:Java Runtime Environment(Java 運(yùn)行環(huán)境)的簡(jiǎn)稱,為 Java 的運(yùn)行提供了所需環(huán)境;
- JVM:Java Virtual Machine(Java虛擬機(jī))的簡(jiǎn)稱,是一種用于計(jì)算設(shè)備的規(guī)范,它是一個(gè)虛構(gòu)出來(lái)的計(jì)算機(jī),是通過(guò)在實(shí)際的計(jì)算機(jī)上仿真模擬各種計(jì)算機(jī)功能來(lái)實(shí)現(xiàn)的,簡(jiǎn)單來(lái)說(shuō)就是所有的 Java 程序都是運(yùn)行在 JVM(Java 虛擬機(jī))上的。
總體來(lái)說(shuō),JDK 提供了一整套的 Java 運(yùn)行和開發(fā)環(huán)境,通常使用對(duì)象為 Java 的開發(fā)者,當(dāng)然 JDK 也包含了 JRE;而 JRE 為 Java 運(yùn)行的最小運(yùn)行單元,一般安裝在 Java 服務(wù)器上,所以 JDK 和 JRE 可以從用途上進(jìn)行理解和區(qū)分。JVM 不同于 JDK 和 JRE,JVM 是 Java 程序運(yùn)行的載體,Java 程序只有通過(guò) JVM 才能正常的運(yùn)行。
4. Java 中如何獲取明天此刻的時(shí)間?
答:JDK 8 之前使用 Calendar.add() 方法獲取,代碼如下:
Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE, 1); System.out.println(calendar.getTime());JDK 8 有兩種獲取明天時(shí)間的方法。
方法一,使用 LocalDateTime.plusDays() 方法獲取,代碼如下:
LocalDateTime today = LocalDateTime.now(); LocalDateTime tomorrow = today.plusDays(1); System.out.println(tomorrow);方法二,使用 LocalDateTime.minusDays() 方法獲取,代碼如下:
LocalDateTime today = LocalDateTime.now(); LocalDateTime tomorrow = today.minusDays(-1); System.out.println(tomorrow);minusDays() 方法為當(dāng)前時(shí)間減去 n 天,傳負(fù)值就相當(dāng)于當(dāng)前時(shí)間加 n 天。
5. Java 中如何跳出多重嵌套循環(huán)?
答:Java 中跳出多重嵌套循環(huán)的兩種方式。
- 方法一:定義一個(gè)標(biāo)號(hào),使用 break 加標(biāo)號(hào)的方式
- 方法二:使用全局變量終止循環(huán)
方法一,示例代碼:
myfor:for (int i = 0; i < 100; i++) {for (int j = 0; j < 100; j++) {System.out.println("J:" + j);if (j == 10) {// 跳出多重循環(huán)break myfor;}} }方法二,示例代碼:
boolean flag = true; for (int i = 0; i < 100 && flag; i++) {for (int j = 0; j < 100; j++) {System.out.println("J:" + j);if (j == 10) {// 跳出多重循環(huán)flag = false;break;}} }6. char 變量能不能存貯一個(gè)中文漢字?為什么?
答:char 變量可以存貯一個(gè)漢字,因?yàn)?Java 中使用的默認(rèn)編碼是 Unicode ,一個(gè) char 類型占 2 個(gè)字節(jié)(16 byte),所以放一個(gè)中文是沒(méi)問(wèn)題的。
7. Java 中會(huì)存在內(nèi)存泄漏嗎?請(qǐng)簡(jiǎn)單描述一下。
答:一個(gè)不再被程序使用的對(duì)象或變量一直被占據(jù)在內(nèi)存中就造成了內(nèi)存泄漏。
Java 中的內(nèi)存泄漏的常見情景如下:
- 長(zhǎng)生命周期對(duì)象持有短生命的引用,比如,緩存系統(tǒng),我們加載了一個(gè)對(duì)象放在緩存中,然后一直不使用這個(gè)緩存,由于緩存的對(duì)象一直被緩存引用得不到釋放,就造成了內(nèi)存泄漏;
- 各種連接未調(diào)用關(guān)閉方法,比如,數(shù)據(jù)庫(kù) Connection 連接,未顯性地關(guān)閉,就會(huì)造成內(nèi)存泄漏;
- 內(nèi)部類持有外部類,如果一個(gè)外部類的實(shí)例對(duì)象的方法返回了一個(gè)內(nèi)部類的實(shí)例對(duì)象,這個(gè)內(nèi)部類對(duì)象被長(zhǎng)期引用了,即使那個(gè)外部類實(shí)例對(duì)象不再被使用,但由于內(nèi)部類持有外部類的實(shí)例對(duì)象,這個(gè)外部類對(duì)象將不會(huì)被垃圾回收,這也會(huì)造成內(nèi)存泄露;
- 改變哈希值,當(dāng)一個(gè)對(duì)象被存儲(chǔ)進(jìn) HashSet 集合中以后,就不能修改這個(gè)對(duì)象中的那些參與計(jì)算哈希值的字段了,否則對(duì)象修改后的哈希值與最初存儲(chǔ)進(jìn) HashSet 集合中時(shí)的哈希值就不同了,在這種情況下,即使在 contains 方法使用該對(duì)象的當(dāng)前引用作為的參數(shù)去 HashSet 集合中檢索對(duì)象,也將返回找不到對(duì)象的結(jié)果,這也會(huì)導(dǎo)致無(wú)法從 HashSet 集合中單獨(dú)刪除當(dāng)前對(duì)象,造成內(nèi)存泄露。
總結(jié)
以上是生活随笔為你收集整理的第 1-1 课:Java 程序是如何执行的?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 多图带你彻底理解Java中的21种锁!
- 下一篇: java美元兑换,(Java实现) 美元