首先給一個簡單的Java示例,源代碼如下:
- public class Main {
- private static int size=1;
- public static void main(String args[]) {
- User u = new User();
- u.setName("李文水");
- u.setPwd("159");
- String name = u.getName();
- String pwd = u.getPwd();
- u = null;
- }
- }
- public class User {
- private String name;
- private String pwd;
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public String getPwd() {
- return pwd;
- }
- public void setPwd(String pwd) {
- this.pwd = pwd;
- }
- }
現在假設這兩個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類並不會被初始化,因為還沒有用它。