原文地址:http://www.zhihu.com/question/34345694
Java源碼為什麼會經過中間步驟轉換為位元組碼,這樣不是增加工作量嗎。直接解釋原始碼一樣跨平台。
為什麼不在解釋運行時直接解釋原始碼,而是位元組碼。
位元組碼更便於虛擬機器讀取,不用在解析字串,所以運行速度比直接解析原始碼快。 文法是會變的,而原始碼中沒有版本資訊,而位元組碼中不但有版本資訊,還可以經由編譯過程抹平一些語言層面的變化(即語言文法雖然有變化,但位元組碼依然遵照原來的規則即可)。 位元組碼也可以由其他語言產生,如Groovy,Clojure,Scala。需要注意的事,既然這些語言可以編譯成位元組碼,也就可以被Java或其他JVM語言調用。 然而歸根到底,沒有必須這麼設計的絕對理由,很多事物之所以會這樣,只是因為被設計成這樣。
Java嚴格說來是“半解釋半編譯”型的語言 Java代碼首先由javac編譯成位元組碼(ByteCode)。ByteCode是JVM唯一能夠識別的指令,JVM將ByteCode翻譯成真正能夠執行的機器碼 位元組碼的規範由JVM規範(The Java® Virtual Machine Specification)定義,JVM在不同的硬體平台上需要有不同實現,以達到所謂“一次編寫,到處運行”的目標。 理論上,完全可以直接解釋源碼,這樣也可以跨平台。而引入位元組碼有額外的好處:
直接執行位元組碼,比解釋源碼再執行,會更快。
產生位元組碼過程中,編譯器可以預先作語法錯誤或者安全性方面的檢查,出錯機會更少。
位元組碼比源碼更加緊湊,檔案尺寸更小,方便網路傳輸。
有些嵌入裝置,不夠資源跑起完整的編譯器,這些裝置只需要嵌入一個小巧的JVM就行了,在額外的平台上編譯源碼。
位元組碼不一定非要java源碼產生,其它一些語言比如scala也可以編譯產生位元組碼。這樣其它語言就可以利用上經過多年發展的JVM。
一切源於更好的設計
1、快
2、跨平台
3、可擴充
4、《the java specification》 和 《 the JVM specification》是分開的,設計之初就承諾支援其他語言編譯成位元組碼,比如 JRuby,scala ,Jython等
CPU從記憶體或者寄存器中讀取資料,而不是直接從硬碟中讀取資料。
和這個道理差不多。
為了跨平台,編譯成的位元組流檔案.class,與硬體和作業系統無關,這是跨平台基礎,然後具體執行,再用各自平台解譯器,解釋成本地機器碼。另外還有一個安全性的問題,編譯的結果本身保證了代碼安全和著作權。
作者:火雨
連結:http://www.zhihu.com/question/34345694/answer/59501996
來源:知乎
著作權歸作者所有,轉載請聯絡作者獲得授權。
其實,Java作為一個進階語言,便於開發人員閱讀和理解代碼,jvm虛擬機器用於執行代碼指令,而指令就不會像原始碼那樣有很強可讀性,另外,class檔案內容緊湊,使用空間小,jvm載入類支援從網路載入class檔案流,這樣可以減少網路頻寬,提高效能。
Javac編譯過程中,並不是簡單的理解為編譯成虛擬機器能夠識別的指令那麼簡單,在編譯過程中,需要對源碼進行詞法分析,文法分析,語義分析,最後產生位元組碼。我們都知道Java語言,記憶體是自動管理的,一個對象執行個體記憶體空間的申請、分配和回收都是虛擬機器自己去管理的。Java記憶體配置有動態記憶體分配,也有靜態記憶體配置,靜態記憶體配置就是在編譯時間候,就確定需要分配的記憶體大小,如類的靜態常量,對於一些大小不可知的對象,只有運行時才能確定需要申請的空間大小。所以靜態分配效能相對動態分配比較高一些。由此看出,Java編譯成位元組碼,除了將源碼編譯成虛擬機器可執行檔位元組碼,也做了一些其他準備工作。
因此,若將源碼替代位元組碼,虛擬機器直接執行源碼的話,要麼程式員將源碼寫成位元組碼那樣的,這樣對程式員不友好,另外就是當虛擬機器載入某個類,或者執行個體化某個對象的時候,虛擬機器做一些與編譯器類似的工作,但是這樣效能會收到很大的影響。
理解的比較淺,可能有很多地方不正確,希望大家一起探討。
Java9 添加了一個新工具,JShell,然後我下了 ea 版本來嘗鮮。應該說從 Java9 開始,Java 就有工具來通過直接解釋源碼運行程式了(指的是表面上,底層應該還是先產生位元組碼然後再運行)。
首先寫個計算 pi 的程式:
<img src="https://pic4.zhimg.com/34a2775021ca4db77ac604d6d84a74b3_b.png" data-rawwidth="859" data-rawheight="326" class="origin_image zh-lightbox-thumb" width="859" data-original="https://pic4.zhimg.com/34a2775021ca4db77ac604d6d84a74b3_r.png">
然後用 JShell 來運行:
<img src="https://pic1.zhimg.com/97078a23dbd40e7a559fb308a83236ac_b.png" data-rawwidth="409" data-rawheight="46" class="content_image" width="409">是的,你沒有看錯,以後 Java 居然也可以當指令碼語言來用了。當然,比起 Scala 和 Groovy,Java寫起來時稍微囉嗦了一點(雖然在這個例子中不是很明顯)。不過,這已經很棒了(畢竟這是 Java 嘛 :) ) 是的,你沒有看錯,以後 Java 居然也可以當指令碼語言來用了。當然,比起 Scala 和 Groovy,Java寫起來時稍微囉嗦了一點(雖然在這個例子中不是很明顯)。不過,這已經很棒了(畢竟這是 Java 嘛 :) )
目前 JShell 的缺點第一在於啟動時間較長(JVM的啟動時間+JShell自身的啟動時間),後期應該會有所改善;第二就是目前內建的方法太少,好吧其實目前只內建了 printf 一個方法...;第三個問題應該是在於Java語言本身,缺少一個 var 關鍵字(JEP 286 考慮為 Java 添加這一特性,應該有希望在 Java10 中能實現, JEP 286: Local-Variable Type Inference)
我就補充點R大的回複。。
Interpreation the source code is OK, but might be slow in many places because of absent of any optimization. By translation, the generate code can be somewhat optimized or simplified.
Norammly, there are a lot of mode for interpretation.
1) Interprete source code directly.
2) Interprete IR, eg. bytecode.
3) between 1) and 2), e.g., interprete AST tree.
4) Translate AST to native code and execute.
5) ..
Many interpreters would mix above four modes. For example, JIT compilation for Java/JavaScript which mixes of bytecode interpretation and native code execution in many projects.
The decison is made for the performance/memory/ factors. For example, the interpreter in CRuby under 1.9 is AST interpreter that does not generate bytecode. However, it generates bytecode since V1.9 for the performance purpose. Similarly, the JRuby+Truffle take the idea of early CRuby. The interpreter walks on the AST tree and then Truffle(Graal) compiles the code and execution. This is also performance purpose.
其實,Java作為一個進階語言,便於開發人員閱讀和理解代碼,jvm虛擬機器用於執行代碼指令,而指令就不會像原始碼那樣有很強可讀性,另外,class檔案內容緊湊,使用空間小,jvm載入類支援從網路載入class檔案流,這樣可以減少網路頻寬,提高效能。
Javac編譯過程中,並不是簡單的理解為編譯成虛擬機器能夠識別的指令那麼簡單,在編譯過程中,需要對源碼進行詞法分析,文法分析,語義分析,最後產生位元組碼。我們都知道Java語言,記憶體是自動管理的,一個對象執行個體記憶體空間的申請、分配和回收都是虛擬機器自己去管理的。Java記憶體配置有動態記憶體分配,也有靜態記憶體配置,靜態記憶體配置就是在編譯時間候,就確定需要分配的記憶體大小,如類的靜態常量,對於一些大小不可知的對象,只有運行時才能確定需要申請的空間大小。所以靜態分配效能相對動態分配比較高一些。由此看出,Java編譯成位元組碼,除了將源碼編譯成虛擬機器可執行檔位元組碼,也做了一些其他準備工作。
因此,若將源碼替代位元組碼,虛擬機器直接執行源碼的話,要麼程式員將源碼寫成位元組碼那樣的,這樣對程式員不友好,另外就是當虛擬機器載入某個類,或者執行個體化某個對象的時候,虛擬機器做一些與編譯器類似的工作,但是這樣效能會收到很大的影響。
理解的比較淺,可能有很多地方不正確,希望大家一起探討。
直接解釋原始碼,而且跨平台。
這樣的程式設計語言真的有啊,php,python。要說效率,還是java高些。
本來編譯型就比解釋型的要快一些,另外jvm在運行時還會最佳化代碼。
原文