Java vs C++
1. Java背景
Java語言最初的設(shè)計(jì)企圖是想用于控制消費(fèi)性電子產(chǎn)品,比如傳呼機(jī),這些都是典型的嵌入設(shè)備。Java的設(shè)計(jì)者企圖建立一個(gè)簡單的、面向?qū)ο蟮摹⒅腔?的、已經(jīng)解譯的、強(qiáng)大的、安全的、架構(gòu)合理的、可移植的、高性能的、多線程的、動(dòng)態(tài)的語言。為使Java對開發(fā)者有吸引力,Sun公司融合了類似于C語言 的語法和結(jié)構(gòu)。然而不管目標(biāo)訂得如何,Java還是被證明不適合于小型的電子設(shè)備,這很大程度上是因?yàn)樗蠖宜俣忍?yīng)用Java程序所需要的處理 能力和內(nèi)存量,對這類設(shè)備來說太昂貴了。
話又說回來,Sun公司設(shè)計(jì)Java時(shí)最重要的是平臺(tái)無關(guān)及網(wǎng)絡(luò)集成。一個(gè)無須更改就能夠在幾種不同硬件和軟件平臺(tái)運(yùn)行的程序,對網(wǎng)絡(luò)環(huán)境(在這種環(huán)境中 用戶希望能夠在辦公室的任何機(jī)器上傳、下載和運(yùn)行程序)來說是一個(gè)理想的程序。對想建立通過網(wǎng)絡(luò)來通信并利用網(wǎng)上資源的分布式程序的開發(fā)者來說,一種在任 何平臺(tái)上都有內(nèi)置的和標(biāo)準(zhǔn)的網(wǎng)絡(luò)支持的語言是一個(gè)大實(shí)惠。
Java設(shè)計(jì)的本意是要簡化C++(原名為olk),但是設(shè)計(jì)之后竟然首先在嵌入式系統(tǒng)中取得了成功(改名為java),而后其強(qiáng)大的網(wǎng)絡(luò)功能使其成為網(wǎng)絡(luò)編程和嵌入式系統(tǒng)中的利器。
2. 嵌入式系統(tǒng)以及個(gè)人電腦上C++與Java
C/C++運(yùn)行效率高,可以對具體的平臺(tái)進(jìn)行優(yōu)化;Java的開發(fā)效率高,移植性好。應(yīng)該根據(jù)具體的應(yīng)用要求,選擇合適的開發(fā)工具。如果是需要執(zhí)行效率非 常高的應(yīng)用,比如說圖形游戲什么的,當(dāng)然再困難也要是用C++。但是,如果是一些下載率很高并且升級很快的個(gè)人應(yīng)用軟件,用JAVA的優(yōu)勢就比較明顯。
2.1. Java對比C++優(yōu)勢
2.1.1. 可移植性強(qiáng)
Java設(shè)計(jì)者考慮的一個(gè)主要問題是程序代碼的持久性和可移植性。程序員面臨的一個(gè)主要問題是,不能保證今天編寫的程序明天能否在同一臺(tái)機(jī)器上順利運(yùn)行。 操作系統(tǒng)升級、處理器升級以及核心系統(tǒng)資源的變化,都可能導(dǎo)致程序無法繼續(xù)運(yùn)行。Java設(shè)計(jì)者對這個(gè)問題做過多種嘗試,Java虛擬機(jī)(JVM)就是試 圖解決這個(gè)問題的。他們的目標(biāo)是“只要寫一次程序,在任何地方、任何時(shí)間該程序永遠(yuǎn)都能運(yùn)行”。在很大程度上,Java實(shí)現(xiàn)了這個(gè)目標(biāo)。
2.1.2. 解釋性和高性能
通過把程序編譯為Java字節(jié)碼這樣一個(gè)中間過程,Java可以產(chǎn)生跨平臺(tái)運(yùn)行的程序。字節(jié)碼可以在提供Java虛擬機(jī)(JVM)的任何一種系統(tǒng)上被解釋 執(zhí)行。Java可以在非常低檔的CPU上順利運(yùn)行。Java確實(shí)是一種解釋性語言,Java的字節(jié)碼經(jīng)過仔細(xì)設(shè)計(jì),因而很容易便能使用JIT(Just- In Time,或JIT)編譯技術(shù)將字節(jié)碼直接轉(zhuǎn)換成高性能的本機(jī)代碼。Java運(yùn)行時(shí)系統(tǒng)在提供這個(gè)特性的同時(shí)仍具有平臺(tái)獨(dú)立性,因而“高效且跨平臺(tái)”對 Java來說不再矛盾。
2.1.3. 健全性
Java程序不可能造成計(jì)算機(jī)崩潰。Java系統(tǒng)仔細(xì)檢測對內(nèi)存的每次訪問,確認(rèn)它是合法的,而且不致引起任何問題。不過,即使Java程序也可能有錯(cuò) 誤。如果出現(xiàn)某種出乎意料之事,程序不會(huì)崩潰,而把該例外拋棄。程序會(huì)發(fā)現(xiàn)這類例外,并加以處理。傳統(tǒng)的程序可以訪問計(jì)算機(jī)的全部內(nèi)存。程序可能(無意識 地)修改內(nèi)存中的任何值,這就會(huì)造成問題。Java程序只能訪問內(nèi)存中允許它們訪問的那些部分,所以Java程序不可能修改不擬修改的值。在Java的情 況下,編程人員不必為內(nèi)存管理操心。Java系統(tǒng)有一個(gè)叫做“無用單元收集器”的內(nèi)置程序,它掃描內(nèi)存,并自動(dòng)釋放那些不再使用的內(nèi)存塊。
2.1.4. 小巧性
由于Java的設(shè)計(jì)是要在小的計(jì)算機(jī)上運(yùn)行,作為一種編程語言來說其系統(tǒng)是相對較小的。它能有效地在4MB以上RAM的PC機(jī)上運(yùn)行。Java翻譯器只占 用幾百KB。這種翻譯器對Java的平臺(tái)無關(guān)性和可移植性是可靠的。由于Java很小,它對內(nèi)存很小的計(jì)算機(jī),如基于Java的PC機(jī),以及電視機(jī)、烤 箱、電話機(jī)及家用計(jì)算機(jī)等,是很理想的。
2.1.5. 可擴(kuò)展性
Java程序可與用其它語言編寫的現(xiàn)存程序庫連接。由于Java數(shù)據(jù)結(jié)構(gòu)與C的數(shù)據(jù)結(jié)構(gòu)的類型極為相似,這是相當(dāng)方便的。最大的問題在于,現(xiàn)有多線程程序 庫為數(shù)不多。Java程序可以聲明某些方法是內(nèi)部的,然后,把這些內(nèi)部方法映射成軟件庫所定義的功能,從而動(dòng)態(tài)地鏈接到虛擬機(jī)。
2.1.6. 安全性高
由于有了JVM,一個(gè)Java應(yīng)用程序與操作系統(tǒng)或硬件完全隔絕,因此計(jì)算機(jī)病毒或其他作祟的代碼就很難獲得對設(shè)備的控制。虛擬機(jī)是主機(jī)設(shè)備和那些可能難以確定其質(zhì)量和可靠性的軟件之間的一個(gè)保護(hù)層。
另外,Java設(shè)計(jì)者從該語言中去掉了指針變量的概念。Java不能任意訪問內(nèi)存,只能讀寫有Java內(nèi)存分配管理系統(tǒng)創(chuàng)建的對象。由于Java編譯器所 強(qiáng)制的嚴(yán)格的分類機(jī)制,從理論上來說,訪問那些未分配給程序的內(nèi)存區(qū)域是不可能的。這個(gè)限制使得寫惡意代碼變得非常困難了。當(dāng)然,這個(gè)保護(hù)并不完善,有人 已經(jīng)在Java安全模型中找到漏洞,但是,JVM確實(shí)提供了一定的保護(hù),使得幾乎不可能直接在硬件上運(yùn)行代碼。
2.1.7. 圖形功能強(qiáng)大
JVM包括一個(gè)龐大的圖形及窗口支持程序包,稱為Abstract Windowing Toolkit(AWT)。用AWT,能在應(yīng)用程序中快速而輕易地創(chuàng)建精致而強(qiáng)大的圖形用戶界面。對于需要精細(xì)的用戶界面的嵌入系統(tǒng)來說,AWT能節(jié)省大量開發(fā)時(shí)間,從而使產(chǎn)品更快地走向市場。
2.2. Java對比C++的缺點(diǎn)
2.2.1. 速度慢
為了實(shí)現(xiàn)跨平臺(tái)的軟件開發(fā),Java設(shè)計(jì)了基于虛擬機(jī)(JVM,JavaVirture Machine)機(jī)制進(jìn)行程序的編譯,確切地說是解釋器和編譯器相結(jié)合,因此在運(yùn)行速度上比較慢,但是通過這幾年的改進(jìn),速度已有了大幅提升,目前速度的 差異仍然有,但在一般的應(yīng)用中看起來并不大。根據(jù)使用的不同,分為J2SE(Java標(biāo)準(zhǔn)版),J2ME(微系統(tǒng)版,嵌入式系統(tǒng)開發(fā),如手機(jī)游戲)和 J2EE(企業(yè)版,ERP、企業(yè)級應(yīng)用開發(fā))三大版本。
Java比典型的腳本語言大為有效,但它比C慢20倍。這對大多數(shù)應(yīng)用是可接受的。不久的將來,代碼生成器就可供利用了,這將使Java程序幾近于用C或C++編寫的程序那么快。
可以用到人們稱為“剛好及時(shí)”(Just-In Time,或JIT)的編譯器,甚至考慮更低級的代碼編譯器。當(dāng)然,低級代碼編譯器會(huì)使編譯好的程序不能跨平臺(tái)執(zhí)行,但同時(shí)也帶來了速度上的提升。這個(gè)速度甚至接近C和C++。
2.2.2. 源代碼保護(hù)機(jī)制不夠安全
在保護(hù)源代碼方面,java是基于解釋一種叫Java字節(jié)碼的中間代碼來運(yùn)行其程序的,而且Jvm比計(jì)算機(jī)的微處理器要簡單的多,文檔也很齊全,結(jié)果造成 其目標(biāo)程序很容易被反編譯,而且所得代碼和其原始代碼十分相似,甚至可以一模一樣,可讀性相當(dāng)好。這就給Java的代碼保護(hù)帶來了不利。
2.2.3. 語言尚不夠成熟
從標(biāo)準(zhǔn)的程序設(shè)計(jì)語言角度來看,Java還很年輕,也很粗糙。如果Java不是由一個(gè)小組開發(fā)的,也許某些錯(cuò)誤和疏忽已經(jīng)被發(fā)現(xiàn)和解決了。在Java亮相 以后,它立即被用于比原來預(yù)期更多的地方。這一切都意味著Java最初的構(gòu)思和實(shí)現(xiàn),雖然堅(jiān)實(shí)和有用,但在安全、大小和性能幾方面仍感欠缺。
2.2.4. 放棄指針
既是優(yōu)點(diǎn)又是缺點(diǎn)。指針是很有效的,但要慎重使用。而java是純面向?qū)ο笳Z言,內(nèi)存操作等都是JVM分配的。放棄指針盡管提高了安全可靠性,但是給開發(fā)帶來不便。
2.2.5. 缺乏直接硬件接口能力。
Java缺乏直接同硬件接口的能力。JVM僅僅是一個(gè)虛擬的機(jī)器,一個(gè)對硬件的軟件抽象,虛擬機(jī)控制與實(shí)際硬件的接口,而我們只能和虛擬機(jī)打交道。
2.2.6. 垃圾收集的系統(tǒng)開銷過大
Java中的自動(dòng)內(nèi)存分配和垃圾收集性能是很實(shí)惠的,但是,從實(shí)時(shí)系統(tǒng)的角度來看,它的問題恰好就在于它是自動(dòng)的。當(dāng)垃圾收集進(jìn)行時(shí),開發(fā)者對系統(tǒng)的控制 就受限了。因?yàn)椋占\(yùn)行時(shí),它凍結(jié)了系統(tǒng)其余部分的處理。這是因?yàn)樗仨氁趦?nèi)存中移動(dòng)對象,并必須在程序再次運(yùn)行前,更新所有引用(指向)那些對 象的程序變量。垃圾收集需要凍結(jié)處理的時(shí)間,具體取決于內(nèi)存量和處理器的速度。很顯然,這對硬實(shí)時(shí)系統(tǒng)是無法接受的,甚至極端時(shí)對軟實(shí)時(shí)系統(tǒng)也是成問題 的。
3. Java反編譯安全性研究
上文提到,Java在源代碼保護(hù)機(jī)制不夠安全。但要實(shí)現(xiàn)java程序的保護(hù),也不是不可能的,經(jīng)研究和總結(jié),至少有三種實(shí)現(xiàn)方式:1、混淆器;2、網(wǎng)絡(luò)加載重要類;3、加密重要類。
3.1. 混淆器
目前,開發(fā)人員使用的比較多的保護(hù)代碼的方法是用混淆器。混淆器是采用一些方法將類,變量,方法,包的名字改為無意義的字符串;使用非法的字符代替符號;貼加一些代碼使反編譯軟件崩潰;貼加一些無關(guān)的指令或永遠(yuǎn)執(zhí)行不到的指令等使反編譯無法成功或所得的代碼可讀性很差。
混淆后,再反編譯所仍然能得到源代碼,但顯然,所得代碼與原始代碼比,變得難以讀懂,代碼中多了其他的方法,文件名等信息也被打亂了。并且,把以上代碼寫進(jìn)非法的字符中,無法通過編譯。
但是,如果在編寫軟件時(shí),在軟件中寫入某些注冊信息,或一些簡單的算法,通過反編譯,還是有可能得到這些信息的,從而未能達(dá)到保護(hù)軟件的目的。反編譯器與混淆器之間的斗爭是永無止盡的。所以從其他角度去保護(hù)java的源代碼是很有必要。
但是這種辦法在網(wǎng)上很容易找到相關(guān)的軟件來重新整理,那么這個(gè)混編只能控制一些本來也沒有辦法動(dòng)您的軟件的人,而對于一些掌握工具的人幾乎是透明的
3.2. 網(wǎng)絡(luò)加載重要類
在Java中提供了一個(gè)ClassLoader類,這個(gè)類可以讓開發(fā)者使用類加載器將所需要的Java字節(jié)碼文件加載到j(luò)vm中。通過重寫這個(gè)類,可以實(shí) 現(xiàn)從網(wǎng)絡(luò)通過url加載Java字節(jié)碼文件。這樣,我們就可以把一些重要的,隱秘的class放在網(wǎng)絡(luò)服務(wù)器上,通過口令去檢驗(yàn)是否有權(quán)限下載該類。從而 實(shí)現(xiàn)Java代碼保護(hù)的目的。其次在Java中正好提供了URLClassLoader這個(gè)類,通過此類,正好可以實(shí)現(xiàn)我們的目的。 URLClassLoader類的基本使用方法是通過一個(gè)URL類型的數(shù)組告訴URLClassLoader類的對象是從什么地方加載類,然后使用 loadclass()方法,從給定的URL中加載字節(jié)碼文件,獲得它的方法,然后再執(zhí)行。
3.3. 加密重要類
使用網(wǎng)絡(luò)加載重要類的方法固然有一定的用處,但是,在遇到無網(wǎng)絡(luò)的情況時(shí),還是無法解決我們的問題。對于這種情況,我們只能把所有文件放在本地計(jì)算機(jī)上。那么,對此我們該怎么做才能保護(hù)好Java代碼呢?
其實(shí),要實(shí)現(xiàn)這一點(diǎn),并不難,只需要對一些重要的類實(shí)行加密就可以了。當(dāng)然,在裝載時(shí),加密的類是需要解密才能被ClassLoader識別的。所以,我 們必須自己創(chuàng)建ClassLoader類。在標(biāo)準(zhǔn)Java api中ClassLoader有幾個(gè)重要的方法。創(chuàng)建定制ClassLoader時(shí),我們只需覆蓋其中的一個(gè),即loadClass,添加獲取原始類文 件數(shù)據(jù)的代碼。這個(gè)方法有兩個(gè)參數(shù):類的名字,以及一個(gè)表示JVM是否要求解析類名字的標(biāo)記(即是否同時(shí)裝入有依賴關(guān)系的類)。如果這個(gè)標(biāo)記為true, 我們只需在返回JVM之前調(diào)用resolveClass。
當(dāng)然,這是需要付出一定的代價(jià)的,就是喪失了Java的最大特點(diǎn)--平臺(tái)無關(guān)性。不過,jni技術(shù)可以用c語言在多種平臺(tái)實(shí)現(xiàn),我們可以在不同的平臺(tái)編寫不同的啟動(dòng)程序。
3.4. 軟件加密鎖
運(yùn)用外殼工具先把調(diào)用用戶的Java解釋器來進(jìn)行加密,也就是說如果要運(yùn)用這個(gè)解釋器就需要有一把特定的加密鎖存在,然后再運(yùn)用它提供的外殼加密工具中的 數(shù)據(jù)加密,把用戶寫好的Java程序(Class或JAR包)當(dāng)作一個(gè)文件來處理而對他進(jìn)行加密,這個(gè)加密是采用的鎖里自帶加密引擎(AES128位)進(jìn) 行加密,加密之后生成新的Java程序。這樣用戶的軟件就只能被用戶保護(hù)過的Java解釋器來進(jìn)行解釋,但是在沒有加密鎖的情況下就不能夠運(yùn)行用戶的軟 件,從而達(dá)到真正保護(hù)用戶的軟件的目的。
3.5. 生成exe文件
利用生成exe文件來防止反編譯,有大量免費(fèi)的工具。
3.6. JADE
由 Sun 中國技術(shù)開發(fā)中心開發(fā)的JADE是一個(gè)保護(hù)Java產(chǎn)品以防止其被反編譯的工具。JADE是能夠解決上述問題和能滿足用戶在這方面需要的第一個(gè)工具。它由五部分組成:混淆器、加密器、封裝器、類編輯器和輸出工具。
3.7. 建議
對于一些需要網(wǎng)絡(luò)支持的軟件來說,可以建立一個(gè)Web站點(diǎn),在站點(diǎn)上存放該軟件的關(guān)鍵類,并且建立用戶管理機(jī)制,用戶直接登陸網(wǎng)站進(jìn)行確認(rèn),是許可用戶, 則發(fā)放解密key文件,讓其下載關(guān)鍵類,在本地解密運(yùn)行。這樣作的優(yōu)點(diǎn)是建立的Web站點(diǎn)可以有效的管理密鑰以及用戶資料。從而起到加強(qiáng)保護(hù)軟件源代碼的 作用,并方便軟件升級。用C/S結(jié)構(gòu)是不錯(cuò)的選擇。或者Java相關(guān)得核心用c來做成控件。
在實(shí)際中,也有大量公司出售自己的反編譯工具來幫助客戶防止商用代碼被反編譯。
4. 深層次一些簡單對比
Java是一種面向?qū)ο蟮木幊陶Z言。除了簡單的類型,如數(shù)字和布爾算子之外,Java中的大部分都是對象。正如任何面向?qū)ο蟮恼Z言一樣,Java代碼也按類組織。每個(gè)類定義一組規(guī)定對象行為的方法。一個(gè)類可以繼承另一個(gè)類的行為。在類的根層次上,通常是類對象。
Java支持單繼承類層次結(jié)構(gòu)。這就是說,每個(gè)類一次只能繼承一個(gè)別的類。有些語言允許多繼承性,但這可能造成混亂,使語言不必要地復(fù)雜化。例如,難以想像,一個(gè)對象會(huì)繼承兩個(gè)完全不同的類的行為。
1、自動(dòng)內(nèi)存管理:Java對于內(nèi)存的分配是動(dòng)態(tài)的,并具有垃圾回收機(jī)制。
2、不在類外定義全局變量。
3、Java中將不再使用goto語句。
4、Java中取消了指針。
5、支持固定位數(shù)的數(shù)據(jù)類型。
6、運(yùn)行時(shí)系統(tǒng)對類型轉(zhuǎn)換進(jìn)行類型相容性檢查。
7、Java不支持頭文件,使用import與其它類通訊。
8、Java中不包含結(jié)構(gòu)和聯(lián)合,所有的內(nèi)容都封裝在類中。
9、Java中不支持宏,它通過final關(guān)鍵字來聲明一個(gè)常量。
10、Java不支持多重繼承,可以通過Java中的接口實(shí)現(xiàn)多重繼承的功能。