Loading AI tools
来自维基百科,自由的百科全书
此條目翻譯品質不佳。 |
C++和Java語言之間的不同可以追溯到它們各自的傳統,它們有著不同的設計目標。
不同的開發目標導致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]
Foo<1>(3);
,如果 Foo 是一個變數,那麼它是一個比較的運算式,但如果 Foo 是一個類範本的名字,那麼它會建立一個物件。C++ | Java |
---|---|
class Foo { // 定义 Foo 类
public:
int x; // 成员变量
Foo(): x(0) { // 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}"
|
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++ | 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;
// 合法,你還是可以修改這個物件
|
if
、while
和 for
里的退出條件)預期的都是一個布爾表達式,但 if(a = 5)
這樣的代碼在 Java 里會導致編譯錯誤,因為沒有從整型到布爾的隱式變窄轉換。如果代碼是 if(a == 5)
的輸錯的情況那麼是很方便發現這個錯誤的。而目前的 C++ 編譯器一般來說只會針對這種情況產生一個警告。+
" 和 "+=
" 運算子,在字串里多載為連接字串。synchronized
這個 Java 的關鍵字為了支援多執行緒應用提供了簡單而安全的的互斥鎖,但同步(synchronized)區只能用 LIFO 的順序離開。Java 也為更高階的多執行緒同步提供了健壯而複雜的庫。在 C++ 里沒有專門為多執行緒定義的主記憶體模型;但第三方庫提供了和 Java 差不多的功能;不過這些 C++ 庫之間差異較大,一致性不好。final
關鍵字使之聲明為非虛的。java.lang.Enum<E>
擴展而來),象其他的類一樣可以定義構造函式,數據成員及方法。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). 使用一個錯誤的參數會在使用它的時候導致一個類錯誤. 在泛型代碼里操作和參數化類型只能按聲明的時候保證安全的方式來使用. 這用失去彈性的代價來換取好得多的類型方面的安全性. |
模板是圖靈完全的(參見 模板超程式設計). | 泛型不是圖靈完全的. |
(a/b)*b + (a%b) == a
. C++ 版本有時候會更快,因為它允許直接使用處理器的截斷方式.想執行一個編譯好的 Java 程序,電腦上要執行JVM;而編譯好的 C++ 程序不需要額外的應用。比較早期的 Java 版本在效能上比靜態編譯的語言如 C++ 差得很多,這是因為用 C++ 是直接編譯成一些機器指令,而當 Java 編譯成位元組碼以後用 JVM 解釋執行的時候又牽涉了不少額外的機器指令。 例如:
Java/C++ 語句 | C++ 生成的代碼 (x86) | Java 生成的位元組碼 |
---|---|---|
vector[i]++; | mov edx,[ebp+4h] mov eax,[ebp+1Ch] |
aload_1 iload_2 |
C++ 在大部分的情況下都比 Java 要快,[7] 有幾個數值方面的基準測試的研究爭辯說 Java 在某些情況下可能會比 C++ 的效能好得多。[8][9][10] 但有人說數值方面的基準測試對於語言的評估是不合適的,因為編譯器都可以做相關的最佳化,甚至可能將被測試的代碼徹底刪除。[11][12][13] 如果涉及到一個真正現實應用的程序,Java 會因為很多原因導致效能變差:[14][15][16]
有人爭論說,和 Java 相比 C++也有很多劣勢:
此外,有爭議的是,花在更複雜的 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]
兩者的對象訪問格式也不一樣。
Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.