No1:java
物理機的執行引擎是直接創建在處理器、硬件、指令集合操做系統層面上的,而虛擬機的執行引擎則是由本身實現的,所以能夠自行制定指令集與執行引擎的結構體系,而且可以執行那些不被硬件直接支持的指令集格式。程序員
No2:安全
執行引擎在執行java代碼的時候可能會有解釋執行(經過解釋器執行)和編譯執行(經過即時編譯器產生本地代碼執行)兩種選擇。數據結構
No3:編碼
棧幀(Stack Frame)是用於支持虛擬機進行方法調用和方法執行的數據結構,它時虛擬機運行時數據區中的虛擬機棧的棧元素。棧幀存儲了方法的局部變量表、操做數棧、動態鏈接和方法返回地址等信息。每個方法從調用開始至執行完成的過程,都對應着一個棧幀在虛擬機裏面從入棧到出棧的過程。spa
No4:操作系統
對於執行引擎來講,在活動線程中,只有位於棧頂的棧幀纔是有效的,稱爲當前棧幀,與這個棧幀相關聯的方法稱爲當前方法。線程
No5:code
局部變量表是一組變量值存儲空間,用於存放方法參數和方法內部定義的局部變量。對象
局部變量表的容量以變量槽(Slot)爲最大單位,每一個Slot都應該能存放一個boolean、byte、char、short、int、float、reference或returnAddress類型的數據。
reference類型表示對一個對象實例的引用,虛擬機能經過這個引用作到兩點
1.今後引用中直接或間接地查找到對象在java堆中的數據存放的起始地址索引
2.此引用中直接或間接地查找到對象所屬數據類型在方法區中的存儲的類型信息
No6:
局部變量表創建在線程的堆棧上,是線程私有的數據,不管讀寫兩個連續的Slot是否爲原子操做,都不會引發數據安全問題。
No7:
虛擬機經過索引定位的方式使用局部變量表,索引值範圍從0開始至局部變量表最大的Slot數量。
No8:
對象本來所佔用的Slot尚未被其餘變量所複用,因此GC Root一部分的局部變量表仍然保持着對它的關聯。若是手動將其設置爲null值(把變量對應的局部變量表Slot清空)System.gc()纔會回收掉內存。
No9:
類變量有兩次賦初始值的過程,一次在準備階段,賦予系統初始值;另一次在初始化階段,賦予程序員定義的初始值。
局部變量若是定義了但沒有賦初始值是不能使用的。
No10:
整數加法的字節碼指令iadd在運行的時候操做數棧中最接近棧頂的兩個元素已經存入了兩個int型的數值,當執行這個指令時,會將這兩個int值出棧並相加,而後將相加的結果入棧。
No11:
操做棧是一個後進先出棧。
No12:
每一個棧幀都包含一個指向運行時常量池中該棧幀所屬方法的引用,持有這個引用是爲了支持方法調用過程當中的動態鏈接(Dynamic Linking)。Class文件的常量池中存有大量的符號引用,字節碼中的方法調用指令就以常量池中指向方法的符號引用做爲參數。這些符號引用一部分會在類加載器階段或者第一次使用的時候就轉化爲直接引用,這種轉化稱爲靜態解析。另一部分將在每一次運行期間轉化爲直接引用,這部分稱爲動態鏈接。
No13:
全部方法調用中的目標方法在Class文件裏面都是一個常量池中的符號引用,在類加載的解析階段,會將其中的一部分符號引用轉化爲直接引用,這種解析能成立的前提是:方法在程序真正運行以前就有一個可肯定的調用版本,而且這個方法的調用版本在運行期是不可改變的。
調用目標在程序代碼寫好、編譯器進行編譯時就必須肯定下來,這類方法的調用稱爲解析;
No14:
在java語言中符合「編譯器可知,運行期不可變」這個要求的方法,主要包括靜態方法和私有方法兩大類。
No15:
分派調用將揭示多態特徵的一些最基本的體現。
No16:
分派----靜態分派:
public class StaticDispatch{ static abstract class Human{} static class Man extends Human{} static class Woman extends Human{} public void sayHello(Human guy) { System.out.println("hello,guy"); } public void sayHello(Man guy) { System.out.println("hello,gentleman"); } public void sayHello(Woamn guy) { System.out.println("hello,lady"); } public static void main(String[] args){ Human man = new Man(); Human woman = new Woman(); StaticDispatch sr = new StaicDispatch(); sr.sayHello(man); sr.sayHello(woman); } }
運行結果
hello.guy
hello.guy
Human man = new Man();
Human爲變量的靜態類型,Man爲變量的實際類型;
靜態類型和實際類型的區別:
1.靜態類型的變化僅僅在使用時發生,變量自己的靜態類型不會被改變,而且最終的靜態類型是在編譯期可知的
2.實際類型變化的結果在運行期纔可肯定,編譯器在編譯程序的時候並不知道一個對象的實際類型是什麼
虛擬機(編譯器)在重載時是經過參數的靜態類型而不是實際類型做爲斷定依據的。靜態類型是編譯期可知的,在編譯階段,javac編譯器會根據參數的靜態類型決定哪一個重載版本。
全部依賴靜態類型來定位方法執行版本的分派動做稱爲靜態分派。靜態分派的典型應用是方法重載,靜態分派發生在編譯階段,所以肯定靜態分派的動做實際上不是由虛擬機來執行的。
public class Overload { public static void sayHello(char arg) { System.out.println("hello char"); } public static void sayHello(int arg) { System.out.println("hello int"); } public static void sayHello(long arg) { System.out.println("hello long"); } public static void sayHello(Character arg) { System.out.println("hello Character"); } public static void sayHello(Serializable arg) { System.out.println("hello Serializable"); } public static void sayHello(Object arg) { System.out.println("hello Object"); } public static void sayHello(char... arg) { System.out.println("hello char..."); } public static void main(String[] args) { sayHello('a'); } }
優先級順序char->int->long->Character->Serializable->Object->char...
No17:
動態分派和重寫有密切的關聯。重載是靜態的,重寫是動態的。
No18:
方法的接受者與方法的參數統稱爲方法的宗量,單分派是根據一個宗量對目標方法進行選擇,多分派是根據多餘一個宗量對目標方法進行選擇。
public class Dispatch{ static class QQ{} static class _360{} public static class Father{ public void hardChoice(QQ arg){ System.out.println("father choose qq"); } public void hardChoice(_360 arg){ System.out.println("father choose 360"); } } public static class Son extends Father{ public void hardChoice(QQ arg){ System.out.println("son choose qq"); } public void hardChoice(_360 arg){ System.out.println("son choose 360"); } } public static void main(String[] args){ Father father = new Father(); Father son = new Son(); father.hardChoice(new _360()); son.hardChoice(new QQ()); } }
運行結果
father choose 360
son choose qq
靜態分派:1.靜態類型是Father仍是Son 2.方法參數是QQ仍是360 因此是多分派類型
動態分派:1.此方法接受者實際類型是Father仍是Son
No19:
總結:java語言是一門靜態多分派、動態單分派的語言。
No20:
動態類型語言的關鍵特徵是它的類型檢查的主體過程是在運行期而不是編譯器。
NegativeArraySizeException是運行時異常,NoClassDefFoundError是鏈接時異常。
No21:
靜態類型語言在編譯期肯定類型,最顯著的好處是編譯器能夠提供嚴謹的類型檢查,這樣與類型相關的問題能在編碼的時候就及時發現,利於穩定性及代碼達到更大規模。
動態類型語言在運行期肯定類型,能夠爲開發人員提供更大的靈活性,某些在靜態類型語言中須要大量「臃腫」代碼來實現的功能,由動態類型語言來實現可能會更加清晰和簡潔,清晰和簡潔一般也就意味着開發效率的提高。