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的相關功能。
相關文章
- Java 編譯期和執行期Java編譯
- 異常-編譯期異常和執行期異常的區別編譯
- C++編譯期多型與執行期多型C++編譯多型
- java mvc 新趨勢——從執行期間類掃描到編譯期間JavaMVC編譯
- java 和c++在編譯和執行上有什麼區別?JavaC++編譯
- 在C,C++,java和python執行時直譯器和編譯器的區別C++JavaPython編譯
- 深入瞭解JVM虛擬機器8:Java的編譯期最佳化與執行期最佳化JVM虛擬機Java編譯
- 解釋和編譯的區別編譯
- Java編譯和執行的命令Java編譯
- (轉)編譯和連結的區別編譯
- 無IDE時編譯和執行JavaIDE編譯Java
- 編譯期型別檢查 in ClojureScript編譯型別
- 【Java】【轉】在命令列中編譯和執行javaJava命令列編譯
- apache動態編譯/靜態編譯區別Apache編譯
- Java之for(;;)和while(true)的區別JavaWhile
- Java之.class和.getClass()的區別Java
- 無IDE下編譯和執行Java的方法IDE編譯Java
- java多執行緒之interrupted()和isInterrupted()的區別(原始碼解讀)Java執行緒原始碼
- Java程式和執行緒關係及區別Java執行緒
- java架構-執行緒和程式的區別Java架構執行緒
- Java虛擬機器11:執行期優化Java虛擬機優化
- Java程式碼編譯和執行的整個過程Java編譯
- [深入理解Java虛擬機器]第十一章 程式編譯與程式碼優化-晚期(執行期)優化Java虛擬機編譯優化
- Java之try-catch和throws的區別Java
- java複習之HashMap和Hashtable的區別JavaHashMap
- [譯] Jquery中 .bind() .live() .delegate() 和 .on() 之間的區別jQuery
- 編譯程式與解釋程式區別?編譯
- gcc 和 g++ 的聯絡和區別,使用 gcc 編譯 c++GC編譯C++
- java執行緒系列---Runnable和Thread的區別Java執行緒thread
- java中不帶package和帶package的編譯執行方式JavaPackage編譯
- Clojure 執行原理之編譯器剖析編譯
- C++物件模型之六 執行期筆記 (轉)C++物件模型筆記
- Java編譯與反編譯Java編譯
- Java之執行緒的生命週期Java執行緒
- Java集合面試題(03) Java中HashMap和HashTable之間區別Java面試題HashMap
- 提前編譯:AOT-Native Image 和執行時編譯 JIT編譯
- Java多執行緒--併發和並行的區別Java執行緒並行
- Java動態編譯和熱更新Java編譯