本節從整體來看一下Java中的精髓.
Java介紹
略
Java和JDK的關系
JDK(Java Development Kit) Java開發工具包,它包括:編譯器,Java運行環境(JRE, Java Runtime Environment), JVM(Java虛擬機),監控和診斷工具等,而Java則表示一種開發語言.
Java程序是怎么執行的?
- 先把Java代碼編譯成字節碼,也就是把 .java類型的文件編譯成 .class類型的文件.這個過程的大致執行流程: Java源代碼 -> 詞法分析器 -> 語法分析器 -> 語義分析器 -> 字節碼生成器 ->最終生成字節碼,其中任何一個節點執行失敗就會造成編譯失敗;
- 把class文件放置到Java虛擬機,這個虛擬機通常指的是Oracle官方自帶的Hotspot JVM;
- Java虛擬機使用類加載器(Class Loader)裝載class文件;
- 類加載完成之后,會進行字節碼校驗,字節碼校驗通過JVM解釋器會把字節碼翻譯成機器碼交由操作系統執行.但不是所有代碼都是解釋執行的,JVM對此做了優化, 比如, 以Hotspot虛擬機來說, 它本身提供了JIT (Just In Time)也就是我們通常所說的動態編譯器,它能夠在運行時將熱點代碼編譯成機器碼,這個時候字節碼就變成了編譯執行.
Java程序執行流程圖如下:
Java虛擬機是如何判定熱點代碼的?
Java虛擬機判定熱點代碼的方式有兩種:
- 基於采樣的熱點判定
主要是虛擬機會周期性的檢查各個線程的棧頂,若某個或某些方法經常出現在棧頂,那這個方法就是"熱點方法".這種判定方式的優點是實現簡單;缺點是很難精確一個方法的熱度,容易受到線程阻塞或外界因素的影響.
- 基於計數器的熱點判定
主要就是虛擬機給每一個方法甚至代碼塊建立了一個計數器,統計方法的執行次數,超過了一定的閾值則標記此方法為熱點方法.
Hotspot虛擬機使用的基於計數器的熱點探測方法.它使用了兩類計數器:方法調用計數器和回邊計數器,當達到一定閾值時就會觸發JIT編譯.
方法調用計數器: 在client模式下的閾值是1500次,Server 是10000次,可以通過虛擬機參數: -XX: CompileThreshold = N 對其進行設置.但是JVM還存在熱度衰減, 時間段內調用方法的次數較少,計數器就減小.
回邊計數器: 主要統計的是方法中循環體代碼執行的次數.
由上面的知識點我們可以看出,要想做到對Java了如指掌,必須要好好學習Java虛擬機,那除了Java虛擬機外,還有哪些知識是我們Java工程師必須掌握的知識呢?
1.Java基礎中的核心內容
字符串和字符串常量池的深入理解,Array的操作和排序算法,深克隆和淺克隆,各種IO操作,反射和動態代理(JDK自身動態代理和CGLIB)等。
2.集合
集合和String是編程中最常用的數據類型,關於集合的知識,主要包含:鏈表(LinkedList)、TreeSet、棧(Stack)、隊列(雙端、阻塞、非阻塞隊列、延遲隊列)、HashMap、TreeMap等,它們的使用和底層存儲數據機構都是熱門內容。
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.數據庫
MySQL常用引擎的掌握、MySQL前綴索引、回表查詢、數據存儲結構、最左匹配原則、MySQL的問題分析和排除方案、MySQL讀寫分離的實現原理以及MySQL的常見優化方案等。Redis的使用場景、緩存雪崩和緩存穿透的解決方案、Redis過期淘汰策略和主從復制的實現方案等。
7.Java虛擬機
虛擬機的組成、垃圾回收算法、各種垃圾回收器的區別、Java虛擬機分析工具的掌握、垃圾回收器常用的調優參數等。
8.其他
常用算法的掌握、設計模式的理解、網絡知識和常見Linux命令的掌握等。
相關題目
1.Java語言都有哪些特點?
答:Java語言包含以下特點。
- 面向對象,程序容易理解,開發簡單,方便;
- 跨平台,可運行在不同服務器類型上,比如:Linux、Windows、Mac等;
- 執行性能好,運行效率高;
- 提供大量API擴展,語言強大;
- 有多線程支持,增加了響應和實時交互能力;
- 安全性好,自帶驗證機制,確保程序的可靠性和安全性。
2.Java跨平台實現的原理是什么?
答:要了解Java跨平台實現原理之前,必須先要了解Java的執行過程,Java的執行過程如下:
Java執行流程:Java源代碼(.java)-> 編譯 -> Java字節碼(.class)->通過JVM(Java虛擬機)運行Java程序。每種類型的服務器都會運行一個JVM,Java程序只需要生成JVM可以執行的代碼即可,JVM底層屏蔽了不同服務器類型之間的差異,從而可以在不同類型的服務器上運行一套Java程序。
3.JDK、JRE、JVM有哪些區別?
答:了解了JDK、JRE、JVM的定義也就明白了它們之間的區別,如下所述。
JDK:Java Development Kit (Java開發工具包)的簡稱,提供了Java的開發環境和運行環境;
JRE:Java Runtime Environment (Java運行環境)的簡稱,為Java的運行提供了所需環境;
JVM:Java Virtual Machine (Java虛擬機)的簡稱,是一種用於計算設備的規范,他是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能來實現的,簡單來說就是所有的Java程序都是運行在JVM(Java虛擬機)上的。
總體來說,JDK提供了一整套的Java運行和開發環境,通常使用對象為Java的開發者,當然JDK也包含了JRE;而JRE為Java運行的最小運行單元,一般安裝在Java服務器上,所以JDK和JRE可以從用途上進行理解和區分。JVM不同於JDK和JRE,JVM是Java程序運行的載體,Java程序只有通過JVM才能正常的運行。
4.Java中如何獲取明天此刻的時間?
答:JDK8之前使用Calendar.add()方法獲取,代碼如下:
Calendar calendar = Calendar.getInstance(); calendar.add(Calendar.DATE,1); System.out.println(calendar.getTime());
JDK8有兩種獲取明天時間的方法。
方法一,使用 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()方法未當前時間減去n天,傳負值就相當於當前時間加n天。
5.Java中如何跳出多重嵌套循環?
答:Java中跳出嵌套循環得兩種方式:
- 方法一:定義一個標號,使用break加標號得方式
- 方法二:使用全局變量終止循環
方法一,示例代碼:
myfor: for (int i = 0; i < 100; i++) { for (int j = 0; j < 100 ; j++) { System.out.println("J:" + j); if (j == 10){ // 跳出多重循環 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){ // 跳出多重循環 flag = false; break; } } }
6.char變量能不能存儲一個中文漢字?為什么?
答:char變量可以存貯一個漢字,因為Java中默認使用的編碼是Unicode,一個char類型占2個字節(16bit),所以放一個中文是沒問題的。
7.Java中會存在內存泄漏嗎?請簡單描述一下。
答:一個不再被程序使用的對象或變量一直被占據在內存中就造成了內存泄漏。
Java中得內存泄漏的常見情景如下:
- 長生命周期對象持有短生命的引用,比如,緩存系統,我們加載了一個對象放在緩存中,然后一直不使用這個緩存,由於緩存的對象一直被緩存引用得不到釋放,就造成了內存泄漏。
- 各種連接未調用關閉方法,比如數據庫Connection連接,未顯性地關閉,就會造成內存泄漏。
- 內部類持有外部類,如果一個外部類的實例對象的方法返回了一個內部類的實例對象,這個內部類對象被長期引用了,即使那個外部類實例對象不再被使用,但由於內部類持有外部類的實例對象,這個外部類對象將不會被垃圾回收,這也會造成內存泄漏;
- 改變哈希值,當一個對象被存儲進HashSet集合中以后,就不能修改這個對象中的那些參與計算哈希值的字段了,否則對象修改后的哈希值與最初存儲進HashSet集合中的哈希值就不同了,在這種情況下,即使在contains方法使用該對象的當前引用作為的參數去HashSet集合中檢索對象,也將返回找不到對象的結果,這也將導致無法從HashSet集合中單獨刪除當前對象,造成內存泄露。