Java和C++的基本差異(轉)

ba發表於2007-08-12
Java和C++的基本差異(轉)[@more@]前言

Java群體每天都在擴大,它既包括一些世界最大的ISV,也包括公司CIO、資訊科技人員、系統分析人員、C/S開發人員、程式設計人員、多媒體設計者、市場行銷人員、教育工作者、經理、影視生產者甚至業餘愛好者等廣泛的使用者。從傳統上看,這樣一些人在一起有效地工作是不多見的。當我們談到開放系統時,我們往往是就已發表的API及規格,或者原始碼的可得性,或者硬體、聯網及作業系統而言的,沒有一個人是從人的開放意義上來談的。Java完成了開放系統的閉合鏈。它開發了人力資源,而反過來又開闢了共同工作的道路。

一談到Java,人們馬上會想起一種類似於C++的、適用於分佈環境的物件導向程式語言,想到這種語言的簡單、穩定、安全、與體系結構無關、可移植、可解釋、高效能、多執行緒和動態性等特徵。這些都是Java作為一種程式設計語言的主要特徵。

Java是由Sun公司的一個技術小組研製出來的。在實現Java語言的過程中,Sun小組的技術人員很快就意識到:C++無法成為一種完全物件導向的、網路化的開發語言。C++是透過給原先的C語言增加物件導向功能而開發出來的,因此,它存在著先天不足。這主要體現在C++種類繁多,功能大量冗餘,同時又沒有任何一種C++編譯器能夠支援它的全部功能。鑑於這種情況,Sun公司的技術人員決定不擴充C++,而開發一種全新的計算機語言(Java的前身Oak)。但是,C++已經成了大多數程式設計人員所熟練掌握的語言,Java的設計顯然不能無視這個現實。如果Java和C++之間的差別過大,那麼程式設計師們在學會這種語言的過程中無疑要花費大量的時間和精力。因此,Java保留了儘可能多的C++風格。

Java自誕生起,為網路使用者創造了無數客戶端的小應用程式,由於這類應用程式效果良好、數量巨大,以至於許多使用者想到Java程式語言時,會在腦海中出現一個不完全正確的印象-Java是用來編寫小的客戶端程式的。其實,隨著技術的進步,Java語言正在逐步改變自己執行效率較低、無法擔任企業關鍵計算任務的形象,不斷向計算技術的核心地帶前進。今天的Java技術正沿著網路滲入各個應用領域。

企業計算:企業計算是Java最重要的技術主題。Sun公司已經公佈了企業JavaBean(EJB,Enterprise JavaBean)的規格,隨後眾多公司開始開發企業應用領域的Java技術。IBM公司也已經為Windows NT開發了IBM HPCJ(High Performance Compiler for Java)12.0版,同時研製了IBM JDK(JavaDevelopment Kit)for Windows NT,Novell公司也在宣佈了一個新的伺服器端的企業Java平臺,而Sun公司也在積極地升級自己的JDK系統,這個形勢表明,Java正在穩步走向企業高階計算。對於Java來說,與其它程式語言爭奪企業計算主力程式設計工具的優勢在於:其一,Java在進行物件導向的程式設計工作時,比其它的程式語言如C++更加簡單,因此保證了程式設計的高效率,減少了程式設計投入;其二,Java虛擬機器技術所提供的"一次程式設計,到處使用"的跨平臺能力非常適合網路環境,這給Java在網路伺服器端的發展提供了便利條件;其三,Java擁有強大的提供商和支持者隊伍,該隊伍包括IBM、Oracle、Novell、Sybase和Netscape等公司。

提速執行:許多企業的應用開發人員非常喜愛Java的語言特性,但是在開發重要系統時,語言特性和執行效率之間的抉擇往往令人傷透腦筋。在關鍵計算中,使用者可能並不在乎資料如何壓縮或者執行的延遲關係如何設定,但是對程式的執行速度卻非常重視,這使廠商將Java的編譯策略開發放在了首位。現在的Java語言,其執行方式已經不僅僅是解釋執行方式了,即時編譯器(JITC、just-in-time compiler)技術和原型編譯技術已經被許多廠家採用,包括Sun、IBM、Oracle以及Netscape等公司在內的技術提供商正在利用這些技術逐步提高Java的執行速度,其中IBM公司早已將Java虛擬機器(JVM,JavaVirtual Machine)、作業系統和硬體的特性有機的結合在一起,非常有效地提高了Java的執行效率。

嵌入計算:嵌入式Java是一個潛力巨大的應用技術,該技術充分發揮了Java小巧靈活的特點。以HP公司為例,該公司以自己的方式製造編譯工具和Java虛擬機器,其目的是將Java嵌入各種裝置,如印表機、醫學監視器和自動提款機等。嵌入裝置依靠一個實時作業系統來處理某一個實時生效的事件,Java被嵌入這些裝置後,透過實時擴充套件(real-time extension)開始發揮作用,使裝置具備了一定的智慧性,增強了嵌入裝置的可管理性和可用性,大大提高了裝置的工作效率。各廠商對這一潛力巨大的市場都非常重視,目前該市場缺乏的是一個標準,如果存在標準的話,相信很快就會有大量使用嵌入Java技術的裝置上市。

微軟剛剛發行的Windows XP放棄了對Java的支援,但Java能夠獨立執行於很多操作平臺上,其中也包括Linux,並且在某些特性上要比在Windows上發揮得更好,我們完全有理由拋棄Windows而選擇使用Linux來做Java開發。現在,你可以左手拿著Linux,右手拿著Java,然後對面帶微笑手裡拿著Windows XP的Bill Gates說:"讓你的XP去見鬼吧!"

對於軟體開發者來講,任何一種程式語言都不可能是完美的。如果希望更好地理解Java語言,最好的方法是把這種語言與其同型別的語言相比較。既然Java類似於C++,把它同C++進行一番比較也是順理成章的事情,哪一個好,哪一個不好,每個開發人員都有各自的看法。我個人認為Java開發要比C++好一些。當然每個人的看法和喜好是不同的。後面的文章將向大家介紹Java和C++的不同和對其的改進。孰強孰弱,大家自然就會明白了。

我們知道,Java一開始採用C++的語法格式,基本上是為了讓程式設計者可以很快地熟悉 Java的語法格式,縮短學習Java的時間,畢竟C和C++仍舊是最多人會的一種程式語言。但是如果我們仔細檢查Java程式語言的許多細節設計,我們可以發現Java去掉了不少C++的特點,並且加入一些新的特性。這些與C++的差異包括:

1.不再有#define、#include等預處理程式(Preprocessor)的功能

C++語言很重要的一個特點就是它的預處理程式。有些其他程式語言雖然也加入了#include的功能,但是還是欠缺處理宏(Macro)的能力。#define的功能在Java中我們可以用定義常數(constant)的方式來取代,而#include在Java中是不需要的,因為在Java中程式在執行時,會把型別資料記錄在物件實體之中,我們不需要靠一些標標頭檔案(header file)來知道我們使用的物件或數值是屬於什麼資料型別。

如果你使用C++語言時,只使用預處理程式的#include和#define功能的話,那麼你大概不會覺得Java這樣的設計對你產生什麼樣的困擾,但是如果你是使用C++語言預處理程式中宏功能的高手,你可能會覺得很不方便,進而懷疑Java如此設計的意義何在。

使用預處理程式雖然可以很方便地達到許多功能,但是站在軟體工程的角度上看,對整個軟體的維護其實是很不利的。由於C++語言中預處理程式的功能太過強大,厲害的程式設計高手常會自行開發一套只有自己看的懂的宏語言,一旦整個軟體要交給其他人去維護,後繼者很難在短時間內瞭解前一個人所寫下的宏功能,增加軟體開發時團隊工作及日後維護的困難度。

另外一點則是C++語言的編譯器所看到的程式程式碼,其實和程式設計者看到的程式程式碼是不同的。程式設計者看到的是尚未經過預處理程式處理過的程式程式碼,而編譯器看到的則是預處理程式處理過的程式程式碼,一旦交給預處理程式處理的宏內容有誤,編譯器產生的錯誤資訊將不會是程式設計師所預料的。而這一點自然也增加了程式在排錯時的困難度。

預處理程式的存在也造成了閱讀程式的不便。如果你想使用別人已經完成的C++語言程式,那麼通常你不但要閱讀他所寫下的檔案,還必須一併查閱上檔案,才能瞭解其程式的全貌。如果換成是Java程式,只要檢視java的程式檔案就夠了。

2.不再有structure、union及typedef

事實上,早在C++中就可以去掉C語言中的structure和union等對複雜資料的自定結構型別,因為類(Class)的定義方式可以完全做到這項功能。而typedef也是不必要的,一切都用類就可以了。雖然C++這樣的設計是為了和C語言相容,但是使用多餘的語言特點不但不必要,而且容易造成對程式認識的混淆。

3.不再有函式

在Java程式語言中,去掉了程式嚮導語言中最重要的單元--函式(Function)。如果我們以物件嚮導的觀念來看待函式,就可以瞭解函式在物件嚮導的概念中,是不必要的。在物件嚮導的程式觀念裡,物件的資料才是真正的主體,而處理物件資料的方法則必須依附在物件內才有意義。因此,去掉函式並不表示不再有子程式等模組化程 序的概念,相反地,是利用物件中的方法來取代函式,再一次強化對嚮導的發展策略。

4.不再有多重繼承(Multiplelnheritance)

在C++中,多重繼承是一項很強的功能,但也是一般人難以掌控的部分。去掉多重繼承雖然降低了Java語言的功能,但是也大幅簡化撰寫程式時的困難度。雖然移除了多重繼承的功能,但是Java提供了interface的方式,可以達到部分多重繼承的功用。所謂的interface基本上定義了一個類的對外溝通的方法原型,以及類內部的常 數,和多重繼承不同之處在於interface並不會定義類方法的內容,以及類中的變數資料。

5.不再有Goto

在程式語言的發展史上,Goto一直是譭譽參半的一項功能。在很多時候使用Goto可以大幅減少不必要的程式程式碼,但是也由於Goto可以很自由地改變程式的流程,如果冒然地使用,更可能造成程式結構混亂的情況。一般來說,正確使用Goto的例子多出現在迴圈內部,想要提早結束某一層迴圈。在C語言中,我們可以使用break 或contine來改變某一層迴圈的流程, 但如果想要改變兩層以上的環執行流程,不是使用Goto就是以多餘的布林(boolean)變數,配合上一串if-then-else的判斷來達成。

Java一方面移除了Goto的功能, 而另一方面同時擴大了break和continue的功能,可以允許多層迴圈的break或continue。如此一來不但避免了濫用Goto的可能性,同時也儲存下Goto的好處。

6.不再有OperatorOverloading

在C++中,Operator Overloading同樣也是一項值得討論的設計。幾乎在所有C++的書中,都會引用一些例子,告訴你使用OperatorOverloading可以使你的程式看起來更為自然。如下面是一個程式設計師自定義的複數類:

//C++中自定義的複數類及0pemtor Overloading
class Complex{
public:
Complex(double real,double image){
Real_number=real;
Image_number=image;
}
Complex operator+(Complex&rhs){
Return Complex(rhs.real_number+real_number,
rhs.image_number+image_,nulnbef);
}
private:
doublereal_number //實部
doublejmage_nunmber; //虛部
}



在這裡,如果你使用+來作為複數的加法符號,大家都不會有疑義,但是如果你使用的是*或》這樣的符號,那麼別人看到你的程式之後,難保不會產生認識上的錯誤。這也是Operator Overloading一大問題,當大家都對運算子賦予自己的定義後,整個程式的可讀性就會大受影響。Operator Overloading的存在並不是必要的,我們一樣可以定義類中的方法來達到同樣的目的,至於Java去掉這項功能的利弊,恐怕就要讀者自己去評斷了。

7.取消自動型別轉換

Java是一個嚴格進行型別檢查的程式語言,對於下面這樣的程式,在C++的編譯器上編譯時最多隻會出現警告的資訊,但是在Java裡則不予透過:

Int aInteger; Double aDouble=2.71828; AInteger = aDouble;


雖然這樣的轉型在C++裡是合法的,但是也會造成資料精確度的損失。Java為了要確定寫程式的人充分地瞭解這點,必須要程式設計強制轉型(type casting),Java的編譯器才會接受:

int aInteger;
doublea Double=2.71828;
aInteger=(int)aDouble;


8.不再有指標

取消指標(Pointer)這樣資料型別,可能會讓許多熟悉C++語言的程式設計師大吃一驚。在C++語言裡,靈活地運用指標是許多程式設計師的得意之作,但是佔整個除錯時間最久的也是指標的問題。配合上C++對記憶體管理的態度,程式設計師必須要自己去追蹤自己向系統要到的記憶體,最後確實地交還給系統,並且在使用指標時,要小心翼翼地注意不要跨過合法的記憶空間,造成Segmentation Fault或General Protection Fault之類的問題。

Java去掉了指標型別,並不表示程式設計師在開發高階資料結構,像堆疊(stack)、 佇列(queue)、二元樹(binarytree)時,都必須要像在傳統Basic上,利用大範圍的陣列來自行模擬系統記憶體,自行建構類似指標的表示方式。

相反地,Java提供了和Lisp語言中相似的Reference型別,透過Reference去讀取配置到的記憶體內容,可以確保不會去讀取到不屬於自己的記憶體空間,而另一方面,程式的執行系統也可以動態地去做記憶體垃圾回收的工作,將沒有被reference參考到的記憶體空間回收給系統使用。

9.和C++連線

不管Java是多麼強大,總是有人需要把它和C++連線起來。因為只要有一個新的程式語言或是軟體開發工具一出現,大家就會問:"它是否具有和原有程式庫連線的能力呢?"也因為C++語言在電腦界中佔了很重要的地位。大家的問題其實就等於是直接問"它是否可以和C++連線?"。目前在Java中,的確提供了和C++語言連線的方法,它的做法基本上是先將C++語言所寫的程式建構成動態連結函式庫(DynamicLinking Library,DLL),再由Java程式去呼叫DLL裡的函式。

這種連線的方式,使得DLL中的函式,從Java的眼光看就是一個"方法"。不過因為這種方法是直接由其他的程式語言所提供,而不是以Java語言所寫的,所以它被稱之為"原生方法"(NativeMethod)。

由於Java Applet一些安全上的限制,所以這種連線外部程式的方法只能用在Java Application內。

小結:

事實上,constant和typedef這兩條語句包含了#define語句的作用。現在,結構和聯合已經被Java的類所代替。刪除這些特性的原因是:由於其希望維持與C語言的向後相容性,C ++的語言規範包含了大量冗餘。比如,類實際上就已經包括了結構和聯合的作用,因此這兩種資料結構完全可以取消。關於#define語句,Java語言規範的制訂者認為:儘管該語句的出發點是為了增強程式的可讀性,但實際效果卻恰恰相反,它常常導致難讀的程式碼,故應該予以取消。Java不再支援獨立函式,因此任何函式都必須封裝到某個類中。由於人們普遍認為, C++所用的超類是非常不穩定的,因此Java拋棄了C++中的多繼承並代之以介面。Java的介面指的是,在別的類看來一個類所能實現的方法。它所顯示的只是一個類的方法或常量和變數 ,而不是這個類的全部結構。

最後,Java還取消了C++中的GOTO語句、運算子過載、自動型別轉換及指標資料型別。 GOTO語句引起的爭議已經有很多年了,可一直陰魂不散,這跟某些程式設計師對該語句一直情有獨鍾有關。C++仍然支援資料型別的自動轉換,但Java要求程式設計人員顯式實現資料型別之間的轉換。自動資料型別轉換使得兩個資料型別互不相容的變數可以相互賦值,而不需要給出顯式說明。這有時會導致一些問題,其中最常見的是精確度損失。比方說,如果把一個帶符號的32位整數賦給一個無符號整數,則所有的結果均為正數。Java的設計者們認為這很容易引起程式錯誤,從而決定不支援這種轉換方式。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/10617731/viewspace-952461/,如需轉載,請註明出處,否則將追究法律責任。

相關文章