国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 編程 > C++ > 正文

Java和C++的對照

2019-11-11 01:59:28
字體:
來源:轉載
供稿:網友

這是一個java語言和C++語言之間的比較。

目錄

  [隱藏] 1設計目標2語言特性2.1語法2.2語義2.3資源管理2.4庫2.5運行時2.6模板 vs. 泛型2.7雜項3性能4所有權控制5參考文獻6外部鏈接

設計目標[編輯]

C++和Java語言之間的不同可以追溯到它們各自的傳統,它們有著不同的設計目標。

C++ 被設計成主要用在系統性應用程序設計上的語言,對C語言進行了擴展。對于C語言這個為運行效率設計的過程式程序設計語言, C++ 特別加上了以下這些特性的支持:靜態類型的面向對象程序設計的支持、異常處理、RAII以及泛型。另外它還加上了一個包含泛型容器和算法的C++庫函數。Java 最開始是被設計用來支持網絡計算。它依賴一個虛擬機來保證安全和可移植性。Java 包含一個可擴展的庫用以提供一個完整的的下層平臺的抽象。Java 是一種靜態面向對象語言,它使用的語法類似C++,但與之不兼容。為了使更多的人到使用更易用的語言,它進行了全新的設計。

不同的開發目標導致 C++ 和 Java 這兩種語言的不同的規則以及設計上的平衡點不同。 如下列出不同點:

C++Java
除了一些比較少見的情況之外和C語言兼容沒有對任何之前的語言向前兼容。但在語法上受 C/C++ 的影響很大
一次編寫多處編譯一次編寫多處運行
允許過程式程序設計和面向對象程序設計必須使用面向對象的程序設計方式
允許直接調用本地的系統庫要通過JNI調用, 或者 JNA
能直接使用底層系統接口在一個保護模式下的虛擬機中運行
只提供對象的類型和類型名是反射的, 允許元程序設計和運行時的動態生成代碼
有多種二進制兼容標準 (例如:微軟和Itanium/GNU)一種二進制兼容標準,允許運行時庫的正確性檢查
可選的自動邊界檢查. (例如: vector 和 string 這兩個容器的 at() 方法)一般都有做邊界檢查。HotSpot (java)(Sun 的虛擬機實現) 可以去掉邊界檢查
支持本地的無符號數學運算不支持本地的無符號數學運算
對所有的數字類型有標準的范圍限制,但字節長度是跟實現相關的。標準化的類型可以用 typdef 定義 (uint8_t, ..., uintptr_t)在所有平臺上對所有的基本類型都有標準的范圍限制和字節長度
支持指針,引用,傳值調用基本類型總是使用傳值調用。對象以可以為空的參考的方式傳遞(相當于在C++里使用指向 class 或者 struct 參數的指針)。[1]
顯式的存儲器管理,但有第三方的框架可以提供垃圾搜集的支持。支持析構函數。自動垃圾搜集(可以手動觸發)。沒有析構函數的概念,對 finalize() 的使用是不推薦的
支持類class,結構struct,聯合union,可以在堆棧或者堆里為它們動態分配存儲器只支持類別,只在堆中為對象分配存儲器。Java SE 6在棧為一些對象分配存儲器的使用了逃逸分析的優化方法
允許顯式的覆蓋(也叫重寫)類型嚴格的類型安全,除了變寬的類型轉換。Java 1.5 開始支持自動類型包裝和解包裝(Autoboxing/Unboxing)
C++庫包括:語言支持,診斷工具,常用工具,字符串,本地化,容器,算法,迭代器,數值,輸入/輸出,C庫。Boost庫提供了更多的功能,包括線程和網絡I/O。用戶必須在一大堆(大部分互相不兼容)第三方GUI或者其他功能庫中進行選擇庫在每次 Java 發布新版本的時候都會更新并增強功能。1.6版本支持:本地化,日志系統,容器和迭代器,算法,GUI 程序設計(但沒有用到系統的GUI),圖形,多線程,網絡,平臺安全,自省機制,動態類別加載,阻塞和非阻塞的I/O,對于xml、XSLT、MIDI也提供了相關接口或者支持類別,數據庫,命名服務(例如 LDAP),密碼學,安全服務(例如 Kerberos),打印服務,WEB 服務。SWT 提供了一個系統相關的GUI的抽象
大部分運算符可以運算符重載運算符的意義一般來說是不可變的,例外是 + 和 += 運算符被字符串重載了
完全的多重繼承,包括虛擬繼承類別只允許單繼承,需要多繼承的情況要使用接口
支持編譯期模板泛型被用來達到和C++模板類似的效果,但由于類型消除它們不能在編譯期間從代碼被編譯成字節碼
支持函數指針,函數對象,lambda(C++11)和接口沒有函數指針機制。替代的概念是接口,Adapter 和 Listener也是被廣泛使用的
沒有標準的代碼內嵌文檔機制。不過有第三方的軟件(例如 Doxygen)Javadoc 標準文檔生成系統
const 關鍵字用來定義不可改變的常量和成員函數final 提供了一個限制版本的 const,等價于 type* const 的對象指針或者 const的基本類型數據。沒有 const 成員函數,也沒有const type* 指針的等價物
支持 goto 語句支持循環標簽(label)和語句塊
源代碼可以寫成平臺無關的(可以被 Windows、BSD、linux、Mac OS X、Solaris 等編譯,不用修改),也可以寫成利用平臺特有的特性。通常被編譯成本地的機器碼被編譯成Java虛擬機的字節碼。和Java平臺相關,但是源代碼一般來說是不依賴操作系統特有的特性的

C++ 是一門強大的語言,設計用在系統程序設計方面。Java語言是設計成簡單易用易學習,并有一個強大的跨平臺的庫。Java庫對一個庫來說相當的大。但Java并不會提供所在平臺的所有特性和接口。C++庫簡單健壯,提供容器和關聯數組的支持。[2]

語言特性[編輯]

語法[編輯]

Java語法是上下文無關文法,可以用一個簡單的LALR語法分析器來分析.而分析C++就復雜多了;例如 Foo<1>(3); ,如果 Foo 是一個變量,那么它是一個比較的表達式,但如果 Foo 是一個類模板的名字,那么它會創建一個對象.C++允許名字空間級別的常量,變量和函數. 而所有這樣的 Java 聲明必須在一個類或者接口當中.在 C++ 的聲明中,一個類名可以用來聲明一個此類對象的值. Java 里沒辦法做到這點. 在Java里對象不是值. 在 Java 的聲明中,一個類名聲明的是對此類的一個對象的引用. 而在 C++ 里與之等價的做法是用 "*" 來聲明一個指針.在 C++ 里,"."操作符將一個對象作為一個左操作參數來訪問這個對象的成員. 因為對象在 Java 里不是值,所有的對象都通過引用來訪問,剛才的做法在 Java 里是無法實現的. 在 Java 里,"." 操作符是將一個對象的引用作為左操作參數來訪問這個對象的成員.在C++中和這種做法等價的是 "->".
C++Java
class Foo {          // 聲明 Foo 類public:    int x;           // 成員變量    Foo(): x(0) {    // Foo 的構造函數Constructor for Foo,    }                //  初始化 x    int bar(int i) { // 成員函數 bar()        return 3*i + x;    }};
class Foo {               // 定義類 Foo    public int x = 0;     // 成員變量,                          //  以及其值的初始化    public Foo() {        // Foo的 構造函數    }    public int bar(int i) {// 成員方法 bar()        return 3*i + x;    }}
Foo a;// 聲明 a 為一個 Foo 類的對象值,// 使用其缺省的構造函數// 如果你想要用其他的構造函數,// 你可以用 "Foo a(args);"
Foo a;// 聲明 a 為一個 Foo 類的對象的引用a = new Foo();// 使用缺省的構造函數初始化// 如果你想要用其他的構造函數,// 你可以用 "Foo a = new Foo(args);"
Foo b = a;// 拷貝 a 的內容到一個新的 Foo 類的變量 b 當中;// 另一種可以選擇的語法是 "Foo b(a)"
Foo b = a.clone();// 拷貝所有a這個實例的成員到b,當且僅當,// Foo 實現了一個 public 的 clone() 方法,// 并且 clone() 返回一個新的這個對象的拷貝
a.x = 5; // 修改 a 對象
a.x = 5; // 修改 a 對象
cout << b.x << endl;// 輸出 0,因為 b 和 a 是兩個對象
System.out.PRintln(b.x);// 輸出 0,因為 b 和 a 是兩個對象
Foo *c;// 聲明 c 為指向一個 Foo 類對象的指針(初始值是// 未定義的;可能指向任何地方)
Foo c;// 聲明 c 為一個指向 Foo 對象的指針// (如果 c 是一個類的成員,那么初始值為空;// 如果 c 是一個局部變量那么你在使用之前必須// 對它進行初始化)
c = new Foo();// 將 c 綁定為一個新的 Foo 對象的引用
c = new Foo();// 將 c 綁定為一個新的 Foo 對象的引用
Foo *d = c;// 將 d 綁定為和 c 同一個對象的引用
Foo d = c;// 將 d 綁定為和 c 同一個對象的引用
c->x = 5;// 修改 c 指向的對象
c.x = 5;// 修改 c 指向的對象
a.bar(5);  // 對 a 調用 Foo::bar()c->bar(5); // 對 *c 調用 Foo::bar()
a.bar(5); // 對 a 調用 Foo.bar()c.bar(5); // 對 c 調用 Foo.bar()
cout << d->x << endl;// 輸出 5,因為 d 引用的對象和 c 一樣
System.out.println(d.x);// 輸出 5,因為 d 引用的對象和 c 一樣
在 C++ 里,聲明一個指向常量的指針(只讀指針)是可能的, 也就是說, 你不能修改這個指針指向的對象的內容. 函數和方法也都保證不會修改用 "const" 關鍵字的指針指向的對象的內容,是強制常量正確性的. 在 Java 里這是不可能做到的. 你可以聲明一個引用為 "final"(就像在 C++ 里聲明一個指針"常量"), 但這只是阻止你重新綁定這個引用; 你還是可以修改這個 "final" 引用指向的對象的.
C++Java
const Foo *a; // 你不能通過 a 修改 a 指向的對象
final Foo a; // 你可以通過 a 修改 a 指向的對象
a = new Foo();
a = new Foo(); // 只能在構造函數里
a->x = 5;// 非法
a.x = 5;// 合法, 你仍然可以修改這個對象
Foo *const b = new Foo();// 你可以聲明一個 "const" 指針
final Foo b = new Foo();// 你可以聲明一個 "final" 引用
b = new Foo();// 非法, 你不能對它再次綁定
b = new Foo();// 非法, 你不能對它再次綁定
b->x = 5;// 合法,你還是可以修改這個對象
b.x = 5;// 合法,你還是可以修改這個對象
C++ 支持 goto 語句; Java 強制結構化流程控制( structured control flow), 依賴break標簽 和 continue標簽 語句來提供類似于 goto 的部分功能. 一些評論者指出這些標簽化的流程控制打破了結構化編程的單退出點的特點.[3]C++ 提供了一些 Java 缺乏的低級特性. 在 C++ 里, 指針可以用來操作特定的內存位置, 這是在寫低級操作系統模塊的時候必須用到的. 類似的, 許多 C++ 編譯期支持內聯匯編,在 Java 里, 這樣的代碼只能放在外來的庫中,而且在調用的時候只能通過JNI來訪問這些外來庫提供的接口.

語義[編輯]

C++ 允許給函數/方法的參數設置缺省值, Java 不提供這個特性. 但是方法重載可以達到同樣的效果.C++ 里最小的編譯單位是一個函數; Java 里最小的編譯單位是一個類. 在 C++ 里, 函數可以被單獨編譯. 在 Java 里, 要編譯和維護單獨的方法需要把它們移到超類或子類或者使用其他的代碼重構的技巧.C++ 允許基本類型之間的一些隱式的轉換, 也允許程序員對于用戶自定義類型相關的隱式轉換規則. 在 Java 里, 只有基本類型之間變寬類型的轉換可以是隱式的; 其余的轉換需要顯式的類型轉換語法.這造成的一個后果是,雖然在 Java 和 C++ 里循環的條件(ifwhile 和 for 里的退出條件)預期的都是一個布爾表達式, 但 if(a = 5) 這樣的代碼在 Java 里會導致編譯錯誤,因為沒有從整型到布爾的隱式變窄轉換. 如果代碼是 if(a == 5) 的輸錯的情況那么是很方便發現這個錯誤的. 而目前的 C++ 編譯器一般來說只會針對這種情況產生一個警告.對于傳參數給函數的情況, C++ 支持引用傳遞和值傳遞. 在 Java 里, 參數總是值傳遞的.[4] 但在 Java 里,所有的非基本類型的值都只是對于對象的引用 (用 C++ 的術語來說, 它們是智能指針). 對象在 Java 里不是作為值直接被使用的,只有對象的引用可以被直接操作; 習慣于將對象當做值直接使用的 C++ 開發者經常會把這個跟引用傳遞搞混.Java 內建的類型在字節寬度和取值范圍上是被虛擬機定義好的; 在 C++ 里, 內建的類型有定義一個最小取值范圍, 但是其他的部分(字節寬度)可以被映射成具體平臺上支持的原生類型.舉個例子, Java 字符是16位的Unicode字符, 字符串是由這樣的字符組成的序列. C++ 提供窄和寬兩種字符,但實際的字符寬度是和平臺相關的, 視所用的字符集而定. 字符串可以由這兩種字符中的一種組成.浮點數及其操作的精度和舍入方式在 C++ 里是平臺相關的. Java 提供了一個可選的嚴格的浮點數模型,保證跨平臺的一致性,不過可能會導致運行時效率比較差.在 C++ 里, 指針可以作為內存地址直接操作. Java 沒有指針 — 它只有對象引用和數組引用,這兩者都不允許直接用來訪問內存地址. 在 C++ 里可以構造一個指向指針的指針,而 Java 的引用只能指向對象.在 C++ 里, 指針可以指向函數或者方法(函數指針). 在 Java 里的等價物是對象或者接口的引用.雖然有使用棧內存分配的對象, C++ 還是支持區域資源管理, 一個用來自動管理內存和其他系統資源的技術,此技術支持確定性對象銷毀(deterministic object destruction). 不過,區域資源管理在 C++ 里是不被保證的;它只是一個設計模式,所以需要依賴程序員遵守相關的規則. Java 通過使用垃圾搜集來支持自動內存管理,但對于其他的系統資源(窗口,通訊端口,線程),如果垃圾搜集器無法決定它們是否不再被用到,那通常還是需要顯式的釋放的.C++ 的用戶可自定義操作符重載的特性在 Java 里是不支持的. 唯一在 Java 里可以重載的操作符是 "+" 和 "+=" 操作符, 在字符串里重載為連接字符串.Java 的標準應用程序接口支持反射和動態加載任意代碼.C++ 支持靜態和動態的庫連接.Java 支持泛型, 其主要目的是提供類型安全的容器. C++ 支持模板, 在泛型編程方面提供了更強的支持.Java 和 C++ 都對基本類型(也叫"內建"類型)和用戶自定義類型(也叫"復合"類型). 在 Java 里, 基本類型只有值的語義,復合類型只有引用的語義. 在 C++ 里所有的值都有值語義,可以創建對于任何類型的引用,這樣就允許通過引用語義來操作對象.C++ 支持任意類型的多重繼承. 在 Java 里一個類只能從單個的類繼承而來,但一個類可以實現多個的接口(換句話說,它支持類型的多重繼承,但對于實現只能單繼承(it supports multiple inheritance of types, but only single inheritance of implementation))。Java 對于類和接口是顯式區分的. 在 C++ 里多重繼承和純虛函數使得定義出類似于 Java 的接口的類是可能的,不過會有少許區別.Java 在語言和標準庫都對多線程有良好的支持. synchronized 這個 Java 的關鍵字為了支持多線程應用提供了簡單而安全的互斥鎖 ,但同步(synchronized)區只能用 LIFO 的順序離開. Java 也為更高階的多線程同步提供了健壯而復雜的庫. 在 C++ 里沒有專門為多線程定義的內存模型; 但第三方庫提供了和 Java 差不多的功能; 不過這些 C++ 庫之間差異較大,一致性不好.C++ 方法可以聲明為虛函數, 虛函數是在運行期根據對象的類型才確定的. C++ 方法缺省情況下不是虛的. 在 Java 里, 方法缺省情況下是虛的, 但可以使用final關鍵字使之聲明為非虛的.C++ 枚舉屬于基本類型,支持和其他整數類型之間的轉換和比較. Java 枚舉實際上是類的實例(它們從 java.lang.Enum<E> 擴展而來),象其他的類一樣可以定義構造函數,數據成員及方法.

資源管理[編輯]

Java 提供了自動化的垃圾搜集. 在 C++ 里內存管理通常通過構造函數,析構函數以及智能指針。C++ 標準允許垃圾搜集,但并不強制要求; 實際使用上垃圾搜集極少被用到. 強制使用自動垃圾搜集導致了在 Java 里編寫實時軟件是困難的.[3]C++ 可以申請任意的內存塊.Java 只能通過對象實例化來申請內存. (注意:在 Java 里, 程序員可以通過創建一個字節數組模擬申請任意的內存塊. 不過 Java 數組仍然是對象.)Java 和 C++ 在資源管理上使用不同的習語. Java 主要依賴只能回收內存的垃圾搜集機制,因為該機制如果用于回收使用中的非內存的系統資源可能是非常危險的。而 C++ 主要依賴 RAII (資源的獲取就是初始化). 這反映了這兩種語言的幾方面的不同:在 C++ 里在棧里申請復合類型的對象是很平常的,一旦退出棧的范圍就會被銷毀. 在 Java 里復合類型的對象總是在堆里申請的內存,而后被垃圾搜集器搜集 (除非在虛擬機里使用了逃逸分析技術來將堆的內存申請轉成棧的.C++ 有析構函數, 而 Java 有finalizer(finalizer). 兩者都會在對象釋放之前被調用, 但是它們有顯著的不同. 一個 C++ 對象的析構函數必須被隱式(棧變量對象的情況)或者顯式地調用來釋放對象. 析構函數在對象釋放之前同步地執行. 同步,協調的反初始化以及釋放在 C++ 里滿足 RAII 的要求. 在 Java 里, 對象的釋放是被垃圾搜集器隱式處理的. 一個 Java 對象的 finalizer 在它被最后一次訪問之后和在實際釋放之前的某個時間點被異步(異步)地調用, 這個調用有可能一直不產生. 非常少的對象需要 finalizer; 只有那些在釋放前必須保證一些清理工作一定要做的對象來說才是需要的 — 典型的情況是:釋放對 JVM 來說是外部的資源. 在 Java 里,企圖安全同步的釋放某些系統資源,只能用顯式的 try/finally 結構來進行.在 C++ 里是有可能有一個迷途指針的 – 過時的對一個已釋放的對象的引用(引用); 試圖使用一個迷途指針的結果是導致程序錯誤. 在 Java 里, 垃圾搜集器不會銷毀一個正在被引用的對象.在 C++ 里未初始化過的基本類型對象是有可能存在的, Java 強制要做缺省初始化.在 C++ 里有可能申請了一個對象,但對它沒有任何引用. 這樣的不可達對象(不可訪問內存)是無法被銷毀的,導致了內存泄漏. 作為對比, 在 Java 里一個對象不會被回收直到它變得不可達(對于用戶程序來說). (注意: 弱引用(弱引用) 是被支持的, 這個特性讓 Java 的垃圾搜集器能夠識別不同 程度的可達性.) 在 Java 里垃圾搜集阻止了很多內存泄漏的情況, 但某些情況下泄漏仍然是可能的.[5]Java 更容易泄漏非內存資源, 而 C++ 的慣用做法更不會導致這種泄漏.

庫[編輯]

C++ 對于許多平臺相關的特性提供了跨平臺的訪問方式. 從 Java 到本地的操作系統和硬件相關的函數的直接訪問需要用到JNI(Java本地接口).

運行時[編輯]

C++ 通常來說會直接被編譯成機器碼,被操作系統直接執行. Java 通常會被編譯成字節碼,被Java虛擬機和解釋器或者即時編譯器編譯成機器碼然后執行.因為表達方式不受限制,低級的 C++ 語言特性(例如:不被檢查的數組訪問,原始指針,類型雙關語(type punning))不能在編譯期間或者運行期間可靠地被檢查. 相關的編程錯誤會導致低級的緩存溢出和段錯誤(存儲器區塊錯誤). 標準模板庫 提供了高級的抽象(例如 vector,list 和 map)來幫助避免這樣的錯誤. 在 Java 里, 低級錯誤不會發生或者會被JVM檢測到并以異常的形式報告給應用.Java 語言在越界訪問數組的時候一般來說會對數組進行邊界檢查(bounds checking). 這消除了導致程序不穩定的一個可能因素,但這是以執行速度更慢一些作為代價的. 在一些情況下,編譯器分析(compiler analysis)可以檢測到不必要的邊界檢查并去掉. C++ 對于原生數組的越界訪問沒有要求特定的處理, 所以需要對于原生數組確認不越界. 但C++ 標準庫里的一部分庫象 std::vector 也提供了可選的邊界檢查. 總的來說, Java 數組是"總是安全;嚴格限制;開銷較多" ,而 C++ 原生數組是"可選的開銷; 完全不限制; 有潛在的不安全."

模板 vs. 泛型[編輯]

C++ 和 Java 都提供泛型編程的能力,分別是模板 和 泛型(Generics in Java). 雖然它們被創造用來解決類似的問題,有類似的語法,但實際上很不一樣.

C++ 模板Java 泛型
類和函數都可以使用模板.類和方法都可以使用泛型.
參數可以是任意類型或者整型.參數只能是能被引用的類型(非基本類型).
在編譯的時候對于每種類型生成類或者函數的拷貝.對于所有類型的參數,只有一個版本的類或者函數生成.
同一個類用不同類型生成的對象在運行期也是不同類型的編譯完成以后類型參數的類型是被消除的; 同一個類用不同類型參數生成的對象在運行期是相同類型的.
想要用到模板類或者函數的實現代碼的話必須 include 它(只是聲明是不夠的).有一個編譯好的類文件里的類或者函數的簽名就足以使用泛型了
模板可以被具體化 -- 可以為某個特定的模板參數提供單獨的實現.泛型不能被具體化.
模板參數可以有缺省參數(default argument)(只針對對于模板類,模板函數是沒有此特性的).泛型類參數無法擁有缺省參數.
不支持通配符. 返回的類型經常是嵌套的 typedef 形式的.如果只用一次,那么支持通配符作為類型參數.
不直接支持設置類型參數的邊界 (即, 不允許說明類型參數必須為某個類型的子類/父類), 但超編程提供了這個特性[6]支持類型參數邊界, 分別以 "extends" 和 "super" 來定義上界和下界; 同時允許定義類型參數之間的繼承關系
允許生成有參模板的類的實例 (如 foo = new Foo<T>, T 為參數)不允許生成有參模板類的實例 (除非使用反射)
泛型類的類型參數無法用在 static 方法和變量上.
static 變量不在在不同的類型參數生成的類之間共享.static 變量在不同類型參數生成的類的對象之間是共享的.
泛型類和函數在聲明時不強制類參數的類限制. 使用錯誤的類參數會導致模板代碼"不工作". 值得注意的是, 如果使用了錯誤的參數, 則錯誤信息將出現在定義模板的代碼處 (而非調用模板的代碼處), 說明 "不支持以該類型作為參數來實例化模板". 這種錯誤信息往往難以幫助人們找出真正的問題所在 (編程時究竟使用了何種 "錯誤的" 參數). 因此, 模板類或者函數的正確使用更依賴于正確的文檔. 超編程以額外的代價提供了這些特性.泛型類和函數在聲明的時候強制了類參數的類限制(Generic classes and functions can enforce type relationships for type parameters in their declaration). 使用一個錯誤的參數會在使用它的時候導致一個類錯誤. 在泛型代碼里操作和參數化類型只能按聲明的時候保證安全的方式來使用. 這用失去彈性的代價來換取好得多的類型方面的安全性.
模板是圖靈完全的 (參見 模板超編程).泛型不是圖靈完全的.

雜項[編輯]

Java 和 C++ 在使代碼在不同的文件分開方面使用了不同的技術. Java 使用了一個包系統,這個系統對所有的程序都要指定了文件名和路徑. 在 Java 里, 編譯器負責導入可執行的類文件. C++ 使用了頭文件源代碼的包含系統來在不同的文件共享聲明.編譯好的 Java 代碼一般來說比 C++ 文件小,因為Java字節碼(Java bytecode)一般來說比機器碼要更緊湊[來源請求],Java 程序都不是靜態鏈接的.C++ 編譯多了一個文本預處理過程, Java 是沒有的. 因此一些用戶在他們的編譯過程之前增加了一個預處理的過程,這樣能更好的支持需要條件編譯的情況.兩個語言里數組都是定長的. 在 Java 里, 數組是一等對象(第一類對象), 而在 C++ 里它們只是它們的基本類型元素的連續的序列, 經常用一個指向第一個元素的指針和一個可選的長度來引用. 在 Java 里, 數組是被邊界檢查的,而且知道它們的長度, 而在 C++ 里你可以將任意的序列當成一個數組. C++ 和 Java 都提供了相關的容器類(分別為std::vector 和 java.util.ArrayList),可以改變大小.Java 的除法和模除操作符是定義成零截斷的. C++ 沒有定義這兩個操作符是零截斷的還是"負無窮截斷"的. 在 Java 里-3/2 總是得到 -1, 但一個 C++ 編譯器可能會返回 -1 或 -2, 視平臺而定. C99 定義了和 Java 一樣的除法方式. 兩種語言都保證對于所有的 a 和 b(b!=0)(當 a 和 b都是整型的時候)(a/b)*b + (a%b) == a. C++ 版本有時候會更快,因為它允許直接使用處理器的截斷方式.整型的長度在 Java 里是已定義好的(int 為 32-bit, long 為 64-bit), 而在 C++ 里整型和指針的長度是和編譯器以及應用二進制接口相關的. 因此仔細編寫的 C++ 代碼可以利用64位處理器的能力而又可以在32位處理器上工作. 但是需要很仔細的用可移植的方式編寫. 作為對比, Java 的固定整型大小使得程序員無法做到這樣,沒辦法利用處理器的字長會導致 Java 在64位處理器上表現較差.

性能[編輯]

想運行一個編譯好的 Java 程序,計算機上要運行JVM;而編譯好的 C++ 程序不需要額外的應用。比較早期的 Java 版本在性能上比靜態編譯的語言如 C++ 差得很多,這是因為用 C++ 是直接編譯成一些機器指令,而當 Java 編譯成字節碼以后用 JVM 解釋執行的時候又牽涉了不少額外的機器指令。 例如:

Java/C++ 語句C++ 生成的代碼 (x86)Java 生成的字節碼
vector[i]++;mov edx,[ebp+4h]

mov eax,[ebp+1Ch]inc dWord ptr [edx+eax*4]

aload_1

iload_2dup2ialoadiconst_1iaddiastore

C++ 在大部分的情況下都比 Java 要快,[7] 有幾個數值方面的基準測試的研究爭辯說 Java 在某些情況下可能會比 C++ 的性能好得多。[8][9][10] 但有人說數值方面的基準測試對于語言的評估是不合適的,因為編譯器都可以做相關的優化,甚至可能將被測試的代碼徹底刪除。[11][12][13] 如果涉及到一個真正現實應用的程序,Java 會因為很多原因導致性能變差:[14][15][16]

所有的對象都在堆里被申請。對于使用小對象的函數來說會導致很大的性能損失,因為在棧里申請內存幾乎沒有性能損失。方法缺省是虛的。這對于小對象來說會因為虛表增加好幾倍的內存使用。它也會引起性能損失,因為 JIT 編譯器不得不對查虛表的過程做額外的優化。即使使用標準的容器依然會有很多的類型轉換,這會引起性能損失,因為需要遍歷整個繼承樹。虛擬機更進一步增加了內存的使用,因此降低了內存的局部性,增加了緩存命中失敗率,從而導致整個程序變慢。缺乏低級細節的操作方式使得開發者無法將程序進一步優化,因為編譯器不支持。[17]

有人爭論說,和 Java 相比 C++也有很多劣勢:

指針使得優化變得困難,因為它們可能指向任意的數據。當然現在這一點也并非完全正確,因為一些現代的編譯器引入了 "嚴格別名" 的規則 [18] 并且支持 C99 的關鍵字 restrict,從而嚴格限制了指針的使用,使其只能用于指向已知的變量 [19]Java 的垃圾搜集和使用malloc/new來申請內存相比能擁有更好的緩存連貫性,因為它的申請一般來說是順序的。然而,始終有爭論認為二者同樣會導致內存的“零碎化”(即多次分配和回收之后內存空間會變得不連續),且并沒有哪一個比對方有更明顯的緩存優勢。運行時編譯可能可以更好的優化代碼,因為可以利用運行時的額外的信息,例如知道代碼是在什么樣的處理器上運行。然而當今的情況也并非完全如此,因為目前最先進的 C++ 編譯器也會針對不同系統生成不同的目標代碼,以期充分利用該系統的計算能力 [20]

此外,有爭議的是,花在更復雜的 C++ 代碼上的 debug 時間太多,用 Java 開發完全可以把這些時間用來優化 Java 代碼。當然對于一個給定的程序來說兩種語言能優化到什么程度也是一方面。最后,對于處理器負擔很重的情況,例如視頻渲染,C++ 能直接訪問硬件,在同樣一個硬件規格下 C++ 總是會比 Java 的表現好很多。

所有權控制[編輯]

C++不是任何一個公司或者組織的商標,不被任何個人擁有。[21] Java原是Sun的商標,現在由甲骨文公司擁有。[22]

C++語言由 ISO/IEC 14882 定義,是一個ISO標準,由 ISO/IEC JTC1/SC22/WG21 委員會發布。 Java語言由 Java Language Specification 定義,這是一本Sun公司(已被甲骨文收購)出版的書。[23]

轉自:https://zh.wikipedia.org/wiki/Java%E5%92%8CC%2B%2B%E7%9A%84%E5%B0%8D%E7%85%A7


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表

圖片精選

主站蜘蛛池模板: 石渠县| 麦盖提县| 公安县| 贵港市| 会昌县| 河津市| 梓潼县| 渭源县| 漳州市| 盐亭县| 长沙市| 中宁县| 游戏| 平山县| 通州市| 江山市| 周宁县| 桐柏县| 镇安县| 天等县| 烟台市| 寿阳县| 石棉县| 泉州市| 商水县| 贞丰县| 南和县| 南康市| 翁源县| 榆中县| 仙桃市| 石门县| 梓潼县| 永新县| 潞城市| 房产| 文登市| 西和县| 积石山| 东方市| 湟中县|