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

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

Java和C++的對照

2019-11-11 03:12:46
字體:
供稿:網(wǎng)友

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

目錄

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

設計目標[編輯]

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

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

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

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

C++ 是一門強大的語言,設計用在系統(tǒng)程序設計方面。Java語言是設計成簡單易用易學習,并有一個強大的跨平臺的庫。Java庫對一個庫來說相當?shù)拇蟆5獼ava并不會提供所在平臺的所有特性和接口。C++庫簡單健壯,提供容器和關聯(lián)數(shù)組的支持。[2]

語言特性[編輯]

語法[編輯]

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

語義[編輯]

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

資源管理[編輯]

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

庫[編輯]

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

運行時[編輯]

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

模板 vs. 泛型[編輯]

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

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

雜項[編輯]

Java 和 C++ 在使代碼在不同的文件分開方面使用了不同的技術. Java 使用了一個包系統(tǒng),這個系統(tǒng)對所有的程序都要指定了文件名和路徑. 在 Java 里, 編譯器負責導入可執(zhí)行的類文件. C++ 使用了頭文件源代碼的包含系統(tǒng)來在不同的文件共享聲明.編譯好的 Java 代碼一般來說比 C++ 文件小,因為Java字節(jié)碼(Java bytecode)一般來說比機器碼要更緊湊[來源請求],Java 程序都不是靜態(tài)鏈接的.C++ 編譯多了一個文本預處理過程, Java 是沒有的. 因此一些用戶在他們的編譯過程之前增加了一個預處理的過程,這樣能更好的支持需要條件編譯的情況.兩個語言里數(shù)組都是定長的. 在 Java 里, 數(shù)組是一等對象(第一類對象), 而在 C++ 里它們只是它們的基本類型元素的連續(xù)的序列, 經(jīng)常用一個指向第一個元素的指針和一個可選的長度來引用. 在 Java 里, 數(shù)組是被邊界檢查的,而且知道它們的長度, 而在 C++ 里你可以將任意的序列當成一個數(shù)組. 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位處理器上表現(xiàn)較差.

性能[編輯]

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

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

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

aload_1

iload_2dup2ialoadiconst_1iaddiastore

C++ 在大部分的情況下都比 Java 要快,[7] 有幾個數(shù)值方面的基準測試的研究爭辯說 Java 在某些情況下可能會比 C++ 的性能好得多。[8][9][10] 但有人說數(shù)值方面的基準測試對于語言的評估是不合適的,因為編譯器都可以做相關的優(yōu)化,甚至可能將被測試的代碼徹底刪除。[11][12][13] 如果涉及到一個真正現(xiàn)實應用的程序,Java 會因為很多原因?qū)е滦阅茏儾睿?sup id="cite_ref-14" class="reference" style="line-height:1; unicode-bidi:isolate; white-space:nowrap">[14][15][16]

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

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

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

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

所有權(quán)控制[編輯]

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

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

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


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

圖片精選

主站蜘蛛池模板: 桃园市| 怀远县| 河东区| 论坛| 道真| 彭泽县| 芮城县| 叙永县| 内江市| 凌海市| 孟村| 蒲江县| 武安市| 那坡县| 揭阳市| 西华县| 新昌县| 桓仁| 秀山| 武宁县| 平南县| 含山县| 临沭县| 资源县| 清镇市| 潞西市| 岚皋县| 府谷县| 连平县| 界首市| 凌源市| 南投县| 长兴县| 丽水市| 泽州县| 岱山县| 拜泉县| 抚顺市| 常熟市| 长春市| 哈尔滨市|