本條目為 Java 語言和 C 語言之間的比較。 設計目標 C 和 Java 語言之間的不同可以追溯到它們各自的傳統，它們有著不同的設計目標。 C 被設計成主要用在系統性應用程式設計上的語言，對 C 語言進行了擴充套件。基於 C 語言這個為執行效率設計的過程式程式設計語言，C 添加了對這些特性的支援：靜態型別的面向物件程式設計的支援、異常處理、RAII 以及泛型。另外它還添加了一個包含泛型容器和演算法的 C 庫函式。 Java 最初被設計用來支援網路計算。它依賴一個虛擬機器來保證安全和可移植性。Java 包含一個可擴充套件的庫以提供一個完整的下層平臺抽象。Java 是一種靜態面向物件語言，它使用的語法和 C 類似，但並不與之相容。為了使更多的人到使用更易用的語言，它進行了全新的設計。 不同的開發目標導致 C 和 Java 這兩種語言的不同的規則以及設計上的平衡點不同。如下列出不同點： C Java 除了一些比較少見的情況之外和 C 語言相容 沒有對任何之前的語言向前相容。但在語法上受 CC 的影響很大 一次編寫多處編譯 一次編寫多處執行 允許過程式程式設計、面向物件程式設計、泛型程式設計、函式式程式設計 必須使用面向物件的程式設計方式 允許直接呼叫原生的系統庫 要透過 JNI 呼叫，或者 JNA 能直接使用底層系統介面 在一個保護模式下的虛擬機器中執行 只提供物件的型別和型別名 是反射的，允許元程式設計和執行時的動態生成程式碼 有多種二進位制相容標準（例如：微軟和 ItaniumGNU） 一種二進位制相容標準，允許執行時庫的正確性檢查 可選的自動邊界檢查（例如：vector 和 string 這兩個容器的 at 方法） 一般都有做邊界檢查。HotSpot java（Sun 的虛擬機器實現）可以去掉邊界檢查 支援原生的無符號數學運算 不支援原生的無符號數學運算 對所有的數字型別有標準的範圍限制，但位元組長度是跟實現相關的。標準化的型別可以用 typdef 定義 uint8_t uintptr_t 在所有平臺上對所有的基本型別都有標準的範圍限制和位元組長度 支援指標，引用，傳值呼叫 基本型別總是使用傳值呼叫。物件以可以為空的引用的方式傳遞（相當於在 C 裡使用指向 class 或者 struct 引數的指標）。 顯式的記憶體管理，但有第三方的框架可以提供垃圾蒐集的支援。支援析搆函式。 自動垃圾蒐集（可以手動觸發）。沒有析構函式的概念，對 finalize 的使用是不推薦的 支援類 class，結構 struct，聯合 union，可以在堆疊或者堆裡為它們動態分配記憶體 只支援類別，只在堆中為物件分配記憶體。Java SE 6 在棧為一些物件分配記憶體的使用了逃逸分析的最佳化方法 允許顯示的覆蓋（也叫重寫）型別 嚴格的型別安全，除了變寬的型別轉換。Java 15 開始支援自動型別包裝和解包裝 AutoboxingUnboxing C 函式庫包括：語言支援，診斷工具，常用工具，字串，本地化，容器，演算法，迭代器，數值，輸入 輸出，C 函式庫。Boost 庫提供了更多的功能，包括執行緒和網路 IO。使用者必須在一大堆（大部分互相不相容）第三方 GUI 或者其他功能庫中進行選擇 函式庫在每次 Java 發布新版本的時候都會更新並增強功能。16 版本支援：本地化，日誌系統，容器和迭代器，演算法，GUI 程式設計（但沒有用到系統的 GUI），圖形，多執行緒，網路，平臺安全，自省機制，動態類別載入，阻塞和非阻塞的 IO，對於 XML、XSLT、MIDI 也提供了相關介面或者支援類別，資料庫，命名服務（例如 LDAP），密碼學，安全服務（例如 Kerberos），列印服務，WEB 服務。SWT 提供了一個系統相關的 GUI 的抽象 大部分運算子可以運算子過載 運運算元的意義一般來說是不可變的，例外是 和 運運算元被字串多載了 完全的多重繼承，包括虛擬繼承 類別只允許單繼承，需要多繼承的情況要使用介面 支援編譯期模板 被用來達到和 C 模板類似的效果，但由於它們不能在編譯期間從程式碼被編譯成位元組碼 支援函式指標，函式物件，lambda C11 和介面 沒有函式指標機制。替代的概念是介面，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 函式庫簡單健壯，提供容器和關聯陣列的支援。 語言特性 語法 Java 語法是上下文無關文法，可以用一個簡單的 LALR 語法分析器來分析。而分析 C 就複雜多了；例如 Foo13 ，如果 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 的建構函式 初始化 x int bar int i 成員函式 bar return 3i x class Foo 定義 Foo 類 public int x 0 成員變數， 以及其值的初始化 public Foo Foo 的 建構函式 public int bar int i 成員方法 bar return 3i 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 aclone 複製所有 a 這個例項的成員到 b 當且僅當， Foo 實現了一個 public 的 clone 方法， 並且 clone 返回一個新的這個物件的複製 ax 5 修改 a 物件 ax 5 修改 a 物件 cout bx endl 輸出 0 因為 b 和 a 是兩個物件 Systemoutprintln bx 輸出 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 同一個物件的引用 cx 5 修改 c 指向的物件 cx 5 修改 c 指向的物件 abar 5 對 a 呼叫 Foobar cbar 5 對 c 呼叫 Foobar abar 5 對 a 呼叫 Foobar cbar 5 對 c 呼叫 Foobar cout dx endl 輸出 5 因為 d 引用的物件和 c 一樣 Systemoutprintln dx 輸出 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 只能在建構函式裡 ax 5 非法 ax 5 合法，你仍然可以修改這個物件 Foo const b new Foo 你可以定義一個 const 指標 final Foo b new Foo 你可以定義一個 final 引用 b new Foo 非法，你不能對它再次繫結 b new Foo 非法，你不能對它再次繫結 bx 5 合法，你還是可以修改這個物件 bx 5 合法，你還是可以修改這個物件 C 支援 goto 語句；Java 強制結構化流程控制，依賴 break 標籤 和 continue 標籤 語句來提供類似於 codegotocode 的部分。 一些評論者指出這些標籤化的流程控制打破了結構化程式設計的單退出點的。點 C 提供了一些 Java 缺乏的低階特性。在 C 裡，指標可以用來操作特定的記憶體位置，這是在寫低階作業系統模組的時候必須用到的。類似的，許多 C 編譯期支援內聯彙編，在 Java 裡，這樣的程式碼只能放在外來的庫中，而且在呼叫的時候只能透過 JNI 來訪問這些外來庫提供的介面 語意 C 允許給函式 方法的引數設定預設值，Java 不提供這個特性。但是方法過載可以達到同樣的效果。 C 裡最小的編譯單位是一個函式；Java 裡最小的編譯單位是一個類。在 C 裡，函式可以被單獨編譯。在 Java 裡，要編譯和維護單獨的方法需要把它們移到超類或子類或者使用其他的程式碼重構的技巧。 C 允許基本型別之間的一些隱式的轉換，也允許程式設計師對於使用者自定義型別相關的隱式轉換規則。在 Java 裡，只有基本型別之間變寬型別的轉換可以是隱式的；其餘的轉換需要顯式的型別轉換語法。 這造成的一個後果是，雖然在 Java 和 C 裡迴圈的條件（if、while 和 for 裡的退出條件）預期的都是一個布林表示式，但 if a 5 這樣的程式碼在 Java 裡會導致編譯錯誤，因為沒有從整型到布林的隱式變窄轉換。如果程式碼是 if a 5 的輸錯的情況那麼是很方便發現這個錯誤的。而目前的 C 編譯器一般來說只會針對這種情況產生一個警告。 對於傳引數給函式的情況，C 支援引用傳遞和值傳遞。在 Java 裡，引數總是值傳遞的。James Gosling Bill Joy Guy Steele and Gilad Bracha The Java language specification third edition AddisonWesley 2005 ISBN 0321246780 see also online edition of the specification 但在 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 裡一個類只能從單個的類繼承而來，但一個類可以實現多個的介面（換句話說，它支援型別的多重繼承，但對於實現只能單繼承）。 Java 對於類和介面是顯式區分的。在 C 裡多重繼承和純虛擬函式使得定義出類似於 Java 的介面的類是可能的，不過會有少許區別。 Java 在語言和標準庫都對多執行緒有良好的支援。synchronized 這個 Java 的關鍵字為了支援多執行緒應用提供了簡單而安全的的互斥鎖，但同步（synchronized）區只能用 LIFO 的順序離開。Java 也為更高階的多執行緒同步提供了健壯而複雜的庫。在 C 裡沒有專門為多執行緒定義的記憶體模型；但第三方庫提供了和 Java 差不多的功能；不過這些 C 庫之間差異較大，一致性不好。 C 方法可以宣告為虛擬函式，虛擬函式是在執行期根據物件的型別才確定的。 C 方法預設情況下不是虛的。在 Java 裡，方法預設情況下是虛的，但可以使用 final 關鍵字使之宣告為非虛的。 C 列舉屬於基本型別，支援和其他整數型別之間的轉換和比較。Java 列舉實際上是類的例項（它們從 javalangEnumE 擴充套件而來），象其他的類一樣可以定義建構函式，資料成員及方法。 資源管理 Java 提供了自動化的垃圾蒐集。在 C 裡記憶體管理通常透過建構函式，解構函式以及智慧指標。C 標準允許垃圾蒐集，但並不強制要求；實際使用上垃圾蒐集極少被用到。強制使用自動垃圾蒐集導致了在 Java 裡編寫實時軟體是困難的。 C 可以申請任意的記憶體塊。Java 只能透過物件例項化來申請記憶體。（注意：在 Java 裡，程式設計師可以透過建立一個位元組陣列模擬申請任意的記憶體塊，不過 Java 陣列仍然是物件。） Java 和 C 在資源管理上使用不同的習語。Java 主要依賴只能回收記憶體的垃圾蒐集機制，因為該機制如果用於回收使用中的非記憶體的系統資源可能是非常危險的。而 C 主要依賴 RAII 資源的獲取就是初始化。這反映了這兩種語言的幾方面的不同： 在 C 裡在棧裡申請複合型別的物件是很平常的，一旦退出棧的範圍就會被銷毀。在 Java 裡複合型別的物件總是在堆裡申請的記憶體，而後被垃圾蒐集器蒐集（除非在虛擬機器裡使用了逃逸分析技術來將堆的記憶體申請轉成棧的。） C 有解構函式，而 Java 有 finalizer 兩者都會在物件釋放之前被呼叫，但是它們有顯著的不同。一個 C 物件的解構函式必須被隱式（棧變數物件的情況）或者顯式地呼叫來釋放物件。解構函式在物件釋放之前同步地執行。同步，協調的反初始化以及釋放在 C 裡滿足 RAII 的要求。在 Java 裡，物件的釋放是被垃圾蒐集器隱式處理的。一個 Java 物件的 finalizer 在它被最後一次訪問之後和在實際釋放之前的某個時間點被非同步（非同步）地呼叫，這個呼叫有可能一直不產生。非常少的物件需要 finalizer；只有那些在釋放前必須保證一些清理工作一定要做的物件來說才是需要的 典型的情況是：釋放對 JVM 來說是外部的資源。在 Java 裡，企圖安全同步的釋放某些系統資源，只能用顯式的 tryfinally 結構來進行 在 C 裡是有可能有一個迷途指標的 過時的對一個已釋放的物件的引用（參照）；試圖使用一個迷途指標的結果是導致程式錯誤。在 Java 裡，垃圾蒐集器不會銷毀一個正在被引用的物件 在 C 裡未初始化過的基本型別物件是有可能存在的，Java 強制要做預設初始化 在 C 裡有可能申請了一個物件，但對它沒有任何引用。這樣的不可達物件（不可訪問記憶體）是無法被銷毀的，導致了記憶體洩漏。作為對比，在 Java 裡一個物件不會被回收直到它變得不可達（對於使用者程式來說） （注意：弱引用 弱引用）是被支援的，這個特性讓 Java 的垃圾蒐集器能夠識別不同 程度的可達性）在 Java 裡垃圾蒐集阻止了很多記憶體洩漏的情況，但某些情況下洩漏仍然是可能的Java memory leaks Catch me if you can by Satish Chandra Gupta Rajeev Palanki IBM DeveloperWorks 16 Aug 2005 Java 更容易洩漏非記憶體資源，而 C 的慣用做法更不會導致這種洩漏 庫 C 對於許多平臺相關的特性提供了跨平臺的訪問方式。從 Java 到原生的作業系統和硬體相關的函式的直接訪問需要用到 JNI（Java 本地介面）。 執行時 C 通常來說會直接被編譯成機器碼，被作業系統直接執行。Java 通常會被編譯成位元組碼，被 Java 虛擬機器和直譯器或者即時編譯器編譯成機器碼然後執行。 因為表達方式不受限制，低階的 C 語言特性（例如：不被檢查的陣列訪問，原始指標，型別雙關語 不能在編譯期間或者執行期間可靠地被檢查。相關的程式設計錯誤會導致低階的快取溢位和段錯誤（記憶體區段錯誤） 標準模板庫 提供了高階的抽象（例如 vectorlist 和 map）來幫助避免這樣的錯誤。在 Java 裡，低階錯誤不會發生或者會被 JVM 檢測到並以異常的形式報告給應用 Java 語言在越界訪問陣列的時候一般來說會對陣列進行邊界檢查 這消除了導致程式不穩定的一個可能因素，但這是以執行速度更慢一些作為代價的。在一些情況下，編譯器分析可以檢測到不必要的邊界檢查並去掉。C 對於原生陣列的越界訪問沒有要求特定的處理，所以需要對於原生陣列確認不越界。但 C 標準庫裡的一部分庫象 stdvector 也提供了可選的邊界檢查。總的來說，Java 陣列是 總是安全；嚴格限制；開銷較多 ，而 C 原生陣列是 可選的開銷； 完全不限制；有潛在的不安全 模板 vs 泛型 C 和 Java 都提供泛型程式設計的能力，分別是模板 和 泛型 雖然它們被創造用來解決類似的問題，有類似的語法，但實際上很不一樣 C 模板 Java 泛型 類和函式都可以使用模板 類和方法都可以使用泛型 引數可以是任意型別或者整型 引數只能是能被引用的型別（非基本型別） 在編譯的時候對於每種型別生成類或者函式的複製 對於所有型別的引數，只有一個版本的類或者函式生成 同一個類用不同型別生成的物件在執行期也是不同型別的 編譯完成以後型別引數的型別是被消除的；同一個類用不同型別引數生成的物件在執行期是相同型別的 想要用到模板類或者函式的實現程式碼的話必須 include 它（只是宣告是不夠的） 有一個編譯好的類檔案裡的類或者函式的簽名就足以使用泛型了 模板可以被具體化 可以為某個特定的模板引數提供單獨的實現 泛型不能被具體化 模板引數可以有預設引數 （只針對對於模板類，模板函式是沒有此特性的） 泛型類引數無法擁有預設引數 不支援萬用字元。返回的型別經常是巢狀的 typedef 形式的 如果只用一次，那麼支援萬用字元作為型別引數 不直接支援設定型別引數的邊界（即，不允許說明型別引數必須為某個型別的子類 父類），但超程式設計提供了這個特性 支援型別引數邊界，分別以 extends 和 super 來定義上界和下界；同時允許定義型別引數之間的繼承關係 允許生成有參模板的類的例項（如 foo new FooT 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 程式都不是靜態連結的 C 編譯多了一個文字預處理過程，Java 是沒有的。因此一些使用者在他們的編譯過程之前增加了一個預處理的過程，這樣能更好的支援需要條件編譯的情況 兩個語言裡陣列都是定長的。在 Java 裡，陣列是頭等物件，而在 C 裡它們只是它們的基本型別元素的連續的序列，經常用一個指向第一個元素的指標和一個可選的長度來引用。在 Java 裡，陣列是被邊界檢查的，而且知道它們的長度，而在 C 裡你可以將任意的序列當成一個數組 C 和 Java 都提供了相關的容器類（分別為 stdvector 和 javautilArrayList），可以改變大小 Java 的除法和模除運算子是定義成零截斷的 C 沒有定義這兩個運算子是零截斷的還是 負無窮截斷 的。在 Java 裡 32 總是得到 1，但一個 C 編譯器可能會返回 1 或 2，視平臺而定 C99 定義了和 Java 一樣的除法方式。兩種語言都保證對於所有的 a 和 b b0（當 a 和 b 都是整型的時候）abb a b a C 版本有時候會更快，因為它允許直接使用處理器的截斷方式 整型的長度在 Java 裡是已定義好的 int 為 32bit long 為 64bit，而在 C 裡整型和指標的長度是和編譯器以及應用二進位制介面相關的。因此仔細編寫的 C 程式碼可以利用 64 位處理器的能力而又可以在 32 位處理器上工作。但是需要很仔細的用可移植的方式編寫。作為對比，Java 的固定整型大小使得程式設計師無法做到這樣，沒辦法利用處理器的字長會導致 Java 在 64 位處理器上表現較差 效能 想執行一個編譯好的 Java 程式，計算機上要執行 JVM；而編譯好的 C 程式不需要額外的應用。比較早期的 Java 版本在效能上比靜態編譯的語言如 C 差得很多，這是因為用 C 是直接編譯成一些機器指令，而當 Java 編譯成位元組碼以後用 JVM 解釋執行的時候又牽涉了不少額外的機器指令。 例如： JavaC 語句 C 生成的程式碼 x86 Java 生成的位元組碼 vector i mov edxebp4h mov eaxebp1Ch inc dword ptr edxeax4 aload_1 iload_2 dup2 iaload iconst_1 iadd iastore C 在大部分的情況下都比 Java 要快， 有幾個數值方面的基準測試的研究爭辯說 Java 在某些情況下可能會比 C 的效能好得多。Performance of Java versus C by JP Lewis and Ulrich Neuman USC Jan 2003 updated 2004Java will be faster than C by Kirk Reinholtz JPL Apr 2001 但有人說數值方面的基準測試對於語言的評估是不合適的，因為編譯器都可以做相關的最佳化，甚至可能將被測試的程式碼徹底刪除。Java not really faster than C benchmark illustrates 如果涉及到一個真正現實應用的程式，Java 會因為很多原因導致效能變差： 所有的物件都在堆裡被申請。對於使用小物件的函式來說會導致很大的效能損失，因為在棧裡申請記憶體幾乎沒有效能損失。 方法預設是虛的。這對於小物件來說會因為虛表增加好幾倍的記憶體使用。它也會引起效能損失，因為 JIT 編譯器不得不對查虛表的過程做額外的最佳化。 即使使用標準的容器依然會有很多的型別轉換，這會引起效能損失，因為需要遍歷整個繼承樹。 虛擬機器更進一步增加了記憶體的使用，因此降低了記憶體的區域性性，增加了快取命中失敗率，從而導致整個程式變慢。 缺乏低階細節的操作方式使得開發者無法將程式進一步最佳化，因為編譯器不支援。 有人爭論說，和 Java 相比 C 也有很多劣勢： 指標使得最佳化變得困難，因為它們可能指向任意的資料。當然現在這一點也並非完全正確，因為一些現代的編譯器引入了 嚴格別名 的規則 並且支援 C99 的關鍵字 restrict，從而嚴格限制了指標的使用，使其只能用於指向已知的變數 Java 的垃圾蒐集和使用 mallocnew 來申請記憶體相比能擁有更好的快取連貫性，因為它的申請一般來說是順序的。然而，始終有爭論認為二者同樣會導致記憶體的 零碎化（即多次分配和回收之後記憶體空間會變得不連續），且並沒有哪一個比對方有更明顯的快取優勢。 執行時編譯可能可以更好的最佳化程式碼，因為可以利用執行時的額外的資訊，例如知道程式碼是在什麼樣的處理器上執行。然而當今的情況也並非完全如此，因為目前最先進的 C 編譯器也會針對不同系統生成不同的目的碼，以期充分利用該系統的計算能力 此外，有爭議的是，花在更復雜的 C 程式碼上的 debug 時間太多，用 Java 開發完全可以把這些時間用來最佳化 Java 程式碼。當然對於一個給定的程式來說兩種語言能最佳化到什麼程度也是一方面。最後，對於處理器負擔很重的情況，例如影片渲染，C 能直接訪問硬體，在同樣一個硬體規格下 C 總是會比 Java 的表現好很多。 所有權控制 C 不是任何一個公司或者組織的商標，不被任何個人擁有。Java 原是 Sun 的商標，現在由甲骨文公司擁有。ZDNet Oracle buys Sun Now owns Java C 語言由 ISOIEC 14882 定義，是一個 ISO 標準，由 ISOIEC JTC1SC22WG21 委員會發布。Java 語言由 Java Language Specification 定義，這是一本 Sun 公司（已被甲骨文收購）出版的書。 其他 兩者的物件訪問格式也不一樣。 參考文獻 外部連結 Java and C Memory Management 一本詳盡的關於面向物件記憶體管理方面的出版物，在記憶體模型上對 Java 和 C 做了比較 How Java Differs from C excerpt from Java in a Nutshell by David Flanagan Java vs C resource management comparison 一份有例子的綜合論文 Java vs C performance again 深入討論 Java 和 C 效能方面的差別 Category 程式語言比較 CategoryJava CategoryC