帶你深入了解Java的運行原理
在Java中引入了虛擬機的概念,即在機器和編譯程式之間加入了一層抽象的虛擬的機器,這臺虛擬的機器在任何平臺上都提供給編譯程式一個的共同的介面,編譯程式只需要面向虛擬機,生成虛擬機能夠理解的代碼,然后由解釋器來將虛擬機代碼轉換為特定系統的機器碼執行,在Java中,這種供虛擬機理解的代碼叫做位元組碼(ByteCode)(class檔案的內容),它不面向任何特定的處理器,只面向虛擬機,每一種平臺的解釋器是不同的,但是實作的虛擬機是相同的,Java源程式經過編譯器編譯后變成位元組碼,位元組碼由虛擬機解釋執行,虛擬機將每一條要執行的位元組碼送給解釋器,解釋器將其翻譯成特定機器上的機器碼,然后在特定的機器上運行,
跨平臺:
話說,在北京,一般都是講北京話的,上海,一般都是將上海話,廣東,廣東話…
現有一公文發出,要全國執行,該當如何?——先統一翻譯成普通話,各地在將普通話版本翻譯成當地的方言,
這里,北京、上海就是不同型別的機器windows,linux…
編譯(javac)就是將公文翻譯成普通話的程序,而編譯出的.class檔案,就是公文的普通話版本,
在執行的時候,各地的翻譯就是jvm,負責將.class轉換成本地能夠理解的方言來執行,
.java→.class→機器碼
java編譯器 (編譯) → 虛擬機(解釋執行) → 解釋器(翻譯) → 機器碼
Java虛擬機(JVM)
Java虛擬機(JVM)是Java Virtual Machine的縮寫,它是一個虛構出來的計算機,是通過在實際的計算機上仿真模擬各種計算機功能模擬來實作的,
Java中,類加載器把一個類裝入JAVA虛擬機需要經過三個步驟來完成:裝載、鏈接、初始化,其中鏈接又分來校驗、準備、決議程序
裝載:查找和匯入.class檔案
鏈接:檢查裝入.class檔案的正確性,然后,java虛擬機為變數分配記憶體,設定默認值
初始化:把符號參考變成直接參考,,,
View Code
現在假設這兩個java源檔案已經被編譯成了CLASS檔案了,我們來看看java虛擬機怎么執行的,
Java虛擬機作業流程:
1.裝載
描敘:Java虛擬機裝載指定的CLASS檔案
結果:形成這個CLASS類的實體物件
程序:java虛擬機使用類裝載器定位到相應的CLASS檔案,然后讀取這個CLASS檔案(一個線性二進制資料流),將它傳入java虛擬機中,緊接著虛擬機提取其中的型別資訊,比如:該類的類名,方法名,變數名,修飾符,方法的回傳型別等等,還有一個重要的東西就是常量池,(常量池保存了該型別的所有常量,包括直接常量和對其他型別,欄位,方法的符號參考)將這些資訊保存在一個叫做方法區的地方,最終形成CLASS類的實體,這個實體存放在記憶體的堆區,它成為了java程式與內部資料結構之間的介面,程式要訪問該型別的資訊,程式就呼叫該型別對應的CLASS實體物件的方法,簡而言之:這個程序就是把一個型別的二進制資料決議為方法區中的內部資料結構,并在堆上建立一個CLASS物件的程序,
示例:裝載Main類
Java虛擬機讀取Main類的CLASS檔案,生產對應的java.lang.Class類的實體,讀取其中的型別資訊,比如修飾符
private,public,static,另外變數
size,name,pwd,User(User即為一個參考)共同構成了這個類的常量池,將這些資訊保存在方法區,
2.鏈接
描述:驗證,準備,決議(可選)
結果:這個型別是正確的,(這里不知道該怎么描述)
程序:
1)驗證:確定型別符合java語言的語意,比如:final類不能有子類,final方法不能被覆寫,確保在型別和超型別之間沒有不兼容的方法宣告(比如兩個方法擁有同樣的名字,引數完全相同,但回傳型別不同),
2)準備:java虛擬機為類變數分配記憶體,設定默認值
3)決議:在型別的常量池中尋找類,介面,欄位和方法的符合參考把這些符號參考替換成直接參考的程序,
示例: 連接Main類
Java虛擬機為size分配記憶體,并賦默認值0.找到常量池中User類的參考,如果User類還沒有被裝載,則裝載并且連接該類,然后將常量池中對User類的參考替換為直接參考,在此時User類并不會被初始化,因為還沒有用它,
3.初始化
描述:初始化一些靜態變數
結果:這個型別可以使用了
程序:可能會呼叫()方法,(這個方法只能夠由java虛擬機呼叫)來初始化該類的靜態變數,在呼叫這個方法前,必須確認該類的超類的()
方法已經被呼叫,示例:初始化Main類
Java虛擬機將Main類的靜態變數賦值為1.
4.使用(執行該類代碼了)
1.User u = new User();(存放在記憶體的堆區)
創建了一個User類實體,實際上是通過這個類的CLASS實體實體化的,方法如下:
User u=(User)Class.forName(“User”).newInstance();
為了方便,用C代替Class.forName(“User”)
2.u.setName(“李文水”); u.setPwd(“159”);
呼叫該類的方法,為該類的變數賦值,Java虛擬機內部呼叫是這樣的,通過方法區找到該方法,利用CLASS實體的如下方法呼叫:
c.getMethod(“setName”).invoke(u,“李文水”);
3.String name = u.getName(); String pwd = u.getPwd();
與第二步類似,不同的是將取得的值分別賦給了變數name和pwd,關鍵是這個值保存在哪里?和實體物件一樣,存放在堆區,這個時候我應該可以看出CLASS實體的作用了,它就是起個中間作用,將程式中的呼叫反應到堆區上資料的變化,
4.u = null;
這個步驟寫出來的目的是了解一下Java虛擬機垃圾回識訓制,(沒有什么實際意義)
Java虛擬機內部會根據一種規則(這個物件是否可以觸及)來判斷這兩個類是否可以回收了?具體形式如下:
當執行 u = null;時這條線就被斬斷了,因此User實體就不可以觸及了,所以java虛擬機就可以回收這個User實體了

最新2020整理收集的一些高頻面試題(都整理成檔案),有很多干貨,包含mysql,netty,spring,執行緒,spring cloud、jvm、原始碼、演算法等詳細講解,也有詳細的學習規劃圖,面試題整理等,
需要獲取這些內容的朋友請加Q君樣:290154296**
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/236065.html
標籤:java
上一篇:零基礎應該怎么自學java?
