java 編譯和運行

編譯期:檢查是否有語法錯誤,如果沒有就將其翻譯成字節碼文件。即.class文件。
運行期:java虛擬機分配內存,解釋執行字節碼文件。

 

從以下代碼開始說明,歡迎大家指正

可以思考下,第一行跟第二行在編譯時期有什麼區別?

java編譯時會做一些優化操作。第一行,因爲是兩個常量做運算,那麼他們的結果就是確定的,即num1的值是確定的。所以在編譯時,編譯器就會直接算出num1的值。第二行則不會,java在運行時期才爲變量分配內存空間。

所以Eclipse編譯得到.class文件,打開class反編譯後可以得到如下代碼:

 

PS:使用Android Studio 編譯器結果有點不一樣,但不影響說明。

 

1、方法重載是在編譯時執行的。因爲在編譯的時候,如果調用了一個重載的方法,那麼編譯時必須確定他調用的方法是哪個。如:當調用evaluate("hello")時候,我們在編譯時就可以確定他調用的method #1.

2、方法的重寫是在運行時進行的。這個也常被稱爲運行時多態的體現。編譯器是沒有辦法知道它調用的到底是那個方法,相反的,只有在jvm執行過程中,才知曉到底是父子類中的哪個方法被調用了。如下:

試想,當有如下一個接口的時候,我們是無法確定到底是調用父類還是子類的方法

3、泛型(類型檢測),這個發生在編譯時。
這也正是泛型的好處之一,可以提前暴露問題,而不是等到運行時出現ClassCastException。編譯器會在編譯時對泛型類型進行檢測,並把它重寫成實際的對象類型(非泛型代碼),這樣就可以被JVM執行了。這個過程被稱爲"類型擦除"。

類型擦除的關鍵在於從泛型類型中清除類型參數的相關信息,並且再必要的時候添加類型檢查和類型轉換的方法。
類型擦除可以簡單的理解爲將泛型java代碼轉換爲普通java代碼,只不過編譯器更直接點,將泛型java代碼直接轉換成普通java字節碼。類型擦除的主要過程如下:
    1). 將所有的泛型參數用其最左邊界(最頂級的父類型)類型替換。
    2). 移除所有的類型參數。
 

4. 註解。註解即有可能是運行時也有可能是編譯時。
如java中的@Override註解就是典型的編譯時註解,他會在編譯時會檢查一些簡單的如拼寫的錯誤(與父類方法不相同)等
同樣的@Test註解是junit框架的註解,他是一個運行時註解,他可以在運行時動態的配置相關信息如timeout等。

5. 異常。異常即有可能是運行時異常,也有可能是編譯時異常。
RuntimeException是一個用於指示編譯器不需要檢查的異常。RuntimeException 是在jvm運行過程中拋出異常的父類。對於運行時異常是不需要再方法中顯示的捕獲或者處理的,如NullPointerException,ArrayIndexOutOfBoundsException
已檢查的異常是被編譯器在編譯時候已經檢查過的異常,這些異常需要在try/catch塊中處理的異常。

6. AOP. Aspects能夠在編譯時,預編譯時以及運行時使用。
    1). 編譯時:當你擁有源碼的時候,AOP編譯器(AspectJ編譯器)能夠編譯源碼並生成編織後的class。這些編織進入的額外功能是在編譯時放進去的。
     2). 預編譯時:織入過程有時候也叫二進制織入,它是用來織入到哪些已經存在的class文件或者jar中的。
     3). 運行時:當被織入的對象已經被加載如jvm中後,可以動態的織入到這些類中一些信息。

7、繼承:繼承是編譯時執行的,它是靜態的。這個過程編譯後就已經確定

8、代理(delegate):也稱動態代理,是在運行時執行。


如何理解"組合優於繼承"這句話?
繼承是一個多態的工具,而非重用工具。在沒有多態關聯關係的對象間,一些程序員傾向於使用繼承來保持重用。但事實是,只有當子類和父類的關係爲"is a"的關係時候,繼承纔會使用。

      1. 不要使用繼承來實現代碼的重用。如果兩者之間沒有"is a"的關係,那麼使用組合來實現重用。當父類的某個方法修改後,子類的相關實現也有可能會被更改。
      2. 不要爲了多態而使用繼承。如果你只是爲了實現多態而採用繼承模式,那麼實際上組合模式更加適合你,而且更加簡潔和靈活。
這也就是爲什麼GoF設計模式中常說"組合優於繼承"的原因。

 

你能區分編譯時繼承和運行時繼承的區別嗎?請列舉例子說明
實際上在java中只支持編譯時繼承java語言原生是不支持運行時時繼承的。一般情況下所謂編譯時繼承如下:
如上有兩個類,其中Child爲Parent的子類。當我們創建一個Parent實例的時候(無論實際對象爲Parent還是Child),編譯器在編譯期間會將其替換成實際類型。所以繼承實際上在編譯時就已經確定了。

而在java中,可以設計通過組合模式來嘗試模擬下所謂的運行時繼承。

在Child類中,其中有一個Parent實例。通過這種方式,我們動態的child類中代理了parent的相關功能。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章