JavaとC++の比較
テンプレートの呼び出しエラー: 廃止されたTemplate:翻訳中が呼び出されています。 {{翻訳中 を {{翻訳中途 としてください。この項目「JavaとC++の比較」は途中まで翻訳されたものです。 テンプレートの呼び出しエラー: 翻訳元の指定は必須です。 1=[翻訳元への固定リンク 翻訳元の版情報] としてください。 |
![]() | この記事は言葉を濁した曖昧な記述になっています。 |
プログラミング言語の比較 |
---|
比較全般 |
基本文法 |
文字列演算 |
文字列関数 |
|
評価戦略 |
|
CとC++の互換性 |
CとPascalの比較 |
C++とJavaの比較 |
C#とJavaの比較 |
C#とVisual Basic .NETの比較 |
設計思想
C++とJava言語との違いは、それら言語の伝統から辿ることができる。
- C++はC言語、手続き型プログラミング言語に静的型付けオブジェクト指向プログラミング言語の特色を追加するために作られ、機械レベルの有能な実行のために設計された。
- Javaはまず第一に組み込みシステム上でネットワークコンピューティングをサポートするために作られた。Javaはポータブルであり、セキュアであり、マルチスレッドであり、分散であり、そしてC++よりもシンプルになるように設計された。Javaの文法はCプログラマに馴染みやすいものが選ばれたが、Cとの直接的な互換性は維持されていない。
C++とJava開発の異なるゴールは異なる言語間の方針とトレードオフに結果として表れた。
The different goals in the development of C++ and Java resulted in different principles and design tradeoffs between the languages.
C++ Java Cとの後方(下位)互換性 一つ前のバージョンだけに後方(下位)互換性 プログラマを当てにする プログラマを守る 低レベル機能に触れる オブジェクトを通してのみメモリアクセス 簡潔な表現 明確な表現 型破壊を明確に許可 型安全性 手続き型 または オブジェクト指向 または 関数型 または 総称型 オブジェクト指向 または 総称型 演算子オーバーロード 演算子はイミュータブルな効果 言語ライブラリとして極端な(ぼんやりとした)能力 機能豊富で容易に使用できる標準ライブラリ
これらの方針は、JavaとC++との間の違いで最も特殊な言語として責任があるC++のCの伝統に結合した。
言語の特徴
文法
- Java文法はシンプルなLALRパーサによって解析できる文脈自由文法である。C++を解析することは、幾分より複雑である。; 例えば、
Foo<1>(3);
はFooが変数であれば、比較シーケンスであるが、Fooがクラスのテンプレート名であればオブジェクトを生成する。
- C++は名前空間レベルの定数、変数、関数を許可する。Javaのようなものはすべて、宣言はクラスやインタフェースの中に書かなければならない。
- C++の
const
は、'読み取り専用'に関し、予示するために適用されたデータであることをはっきりと示す。Javaのfinal
は、変数が再び割り当てられないことをはっきりと示す。const int
対final int
のような基本型として、これらは全く同じであるが、複雑なクラスとしては、それらは異なる:
C++ Java const Rectangle r;
final Rectangle r = new Rectangle();
r= anotherRectangle; //
ILLEGALr = anotherRectangle; //
ILLEGALr.x = 5; //
'誤り'。 r は定数 Rectangler.x = 5; //
'正しい', rは依然として同じ長方形を参照している。
- C++は
goto文
をサポートする。; Javaはサポートしないが、ラベル付break文とラベル付contunue文を、構造上ややgotoライクな機能サポートする。実際には、Javaは、理解を簡単にするコードを目的とするとともに構造制御フローを強要する。 - C++はJavaが持たないやや低レベルな特徴を提供する。C++には、特有のメモリ記憶位置や低レベルオペレーティングシステムコンポーネントを書くために必要なタスクを操るのに役立つポインタがある。同様にして、多くのC++コンパイラはインラインアセンブラをサポートする。Javaには、
外部ライブラリに存在しなければならないコードのようなものはすべて、Java Native Interfaceを通してアクセスされた。そこには、呼び出しのたびに、重大なオーバーヘッドがある。
暗黙になるネイティブ型の精度が大きくなる型変換(ワイデニング変換)のみを許可する。;他の変換は文法で明示的キャストを要求する。
- 関数の引数を渡すとき、C++は参照渡しと値渡し両方をサポートする。Cでは、プログラマは値引数と間接参照さとともに参照引数をシミュレートできる。Javaではすべての引数は値渡しであるが、オブジェクト(非プリミティブ変数)の引数は参照になり、これは間接参照が言語に備わっていることを意味する。
- 一般的に、Javaに組み込まれている型は指定されたサイズと領域をもつ。;だが一方、C++の型はなりうるサイズや領域、作用の多様性を持ち、同じコンパイラで異なるバージョンであっても変える、または、コンパイラの切り替え経由で設定変更可能になりうる。
- 特に、Javaの文字は16ビットUnicode文字であり、文字列はそのような文字の連続を構成する。C++は2バイト文字と1バイト文字両方を利用可能であるが、各々の実際の文字サイズは使われている文字セットとして、プラットフォームに依存する。文字列は何れの型にもなりうる。
- C++にある浮動小数点数の丸め誤差と精度と演算はプラットフォームに依存する。Javaはプラットフォームを渡る一貫した結果を保証する高精度浮動小数点モデルを提供するけれども、通常は最適な浮動小数点演算を許可するために非常に寛大な演算モードが使われる。
C++ではポインタはメモリアドレスを直接操作できる。Javaはメモリアドレスを直接操作できるポインタを持っていない— オブジェクトの参照と配列参照だけはポインタを持ち、どちらもメモリアドレスの直接アクセスを許可しない。C++ではポインタのポインタを構築できるが、Javaではオブジェクトにアクセスするときだけ参照する。 C++では配列は最初の要素と長さがポインタとして与えられ、それはサブ配列を効率よく参照できることを意味するが、配列外アクセスをチェックすることは殆ど不可能である。Javaでは配列は、長さがあらかじめ決められ、サブ配列への参照がやっかいであり、強制的に配列外アクセスをチェックされたファーストクラスオブジェクトである。
Javaではこれと同等のメカニズムはオブジェクトやインタフェース参照を使用する。
- C++はプログラマが定義した演算子オーバロードを特徴づける。Javaにはオーバーロードされた演算子は加算だけでなく文字列連結が可能な"
+
" と "+=
" だけである。 - Javaはリフレクション (情報工学)や任意に新しいコードを動的ロードする機能をサポートする標準APIを特徴づける。
- Javaは総称型を持つ。C++はtemplateを持つ。
JavaとC++双方は、ネイティブ型(これらも"基本的な"または"ビルトイン"型として知られる)とユーザ定義型(これも"複合"型として知られる)で相違を見分る。Javaでは、ネイティブ型は値のセマンティックスだけを持ち、複合型は参照のセマンティックスだけを持つ。C++では、すべての型が値のセマンティックスを持つが、参照は、参照セマンティックスを通して操作されたオブジェクトを許可したオブジェクトによって作ることができる。
- C++は任意のクラスの多重継承をサポートする。Javaは型の体重継承をサポートするが、実装は単一継承のみをサポートする。Javaでは、クラスは一つのクラスからのみ受け継ぐことができるが、クラスは多重インタフェースを実装することができる。
- Javaはインタフェースとクラスとの相違をはっきりと見分ける。C++では、Javaではインタフェースが行う機能を、多重継承と純粋仮想関数(Javaでいうところの抽象クラス)を使って、クラスを定義することで可能にする。
Javaはマルチスレッドをサポートした標準ライブラリと言語を持つ。synchronized
Java予約語はマルチスレッドアプリケーションをサポートするシンプルでセキュアな相互排他ロック(Mutex)を提供するが、synchronized セクションはLIFOオーダーで残されなければならない。ましてや、フレキシブルなMutexロックメカニズムは、一般にマルチスレッドメモリモデルが定義されていないC++のライブラリを通して可能になる。
リソース管理
- Javaは自動ガーベッジコレクションを要求する。C++のメモリ管理は普通、手動で行われるか、スマートポインタを通して行われる。C++標準はガーベッジコレクションを許可するが、それを要求しない。; ガーベッジコレクションは実際には滅多に使われない。オブジェクトを再配置する許可を与えたとき、現在のガーベッジコレクタは明示的解放を使用して全体のアプリケーションスペースと時間効率を改善する。
- C++は任意のメモリブロックを割り当てる。Javaはオブジェクトインスタンス化を通してのみメモリを割り当てる。(注、Javaでは、バイト配列を作ることで、プログラマが任意のブロック割り当てをシミュレートできる。ない、Javaの配列はオブジェクトである。)
- JavaとC++はリソース管理に異なるイディオムを使用する。Javaは主に、メモリの再生だけができ、他のリソース上では最近の場面になるかもしれないガーベッジコレクションに頼る。だが、C++は主にRAII (Resource Acquisition Is Initialization)イディオムに頼る。これは二つの言語間で様々な違いをあらわしてくれる。:
- C++では、範囲外で破棄されたローカルスタックバウンド変数として複合型割り当てオブジェクトが共有されている。Javaでは複合型は常にヒープに割り当てられ、ガーベッジコレクタによって回収される(ヒープ領域をスタック領域に変換するエスケープ解析を使用する仮想マシンでは除く)。
- C++はデストラクタを持っているが、Javaは[[ファイナライザ]を持っている。双方はオブジェクトの解放時に優先的に呼び出されるが、それらは重大性が異する。C++オブジェクトのデストラクタは暗黙(スタックバウンド変数の場合)または明示的にオブジェクトを解放するためによびだされてなければならない。デストラクタはオブジェクトが解放された時点で同期的に実行される。同期は、C++では非初期化と解放に調和する。したがってRAIIイディオムを満たす。Javaでは、オブジェクト解放はガーベッジコレクタによって暗黙のうちに解放される。Javaオブジェクトのファイナライザは、最後にアクセスされた後と、実際に解放される前に、ときどき非同期に呼び出されるが、決して何も起こらないかも知れない。非常に僅かしかないオブジェクトはファイナライザを要求する。;ファイナライザは解放状態を優先するオブジェクトの多少のクリーンナップを保証しなければならないオブジェクトによって要求されるだけである。—だいたいは、JVM外のリソースへ放出される。Javaでは安全な同期によるリソース解放は、try/finally文を構築して明示的に行われなければならない。
- C++では、dangling pointerを持つことが可能である。– オブジェクトへの参照は解放されている。; dangling pointerの使用を試みることは、大抵はプログラムの失敗が結果となっておこるときである。Javaでは、ガーベッジコレクタは参照されているオブジェクトを解放しないだろう。
- C++では初期化されていないプリミティブなオブジェクトを持つことが可能である。Javaはデフォルトの初期化を共生する。
- C++には領域を割り当てられたオブジェクトを持つことが可能であるが、到達不可能である。到達不可能オブジェクトはそのオブジェクトが、到達でききそれを参照できないことである。到達不可能オブジェクトは破解放(破棄)することができず、メモリリークを引き起こす。それとは対照的に、Javaではオブジェクトは、それがユーザプログラムによって到達不可能になるまでガーベッジコレクタによって解放される。(注: 異なる到達可能性の強さを考慮に入れた、Javaのガーベッジコレクタとともに働く、弱い参照がサポートされている。) Javaにあるガーベッジコレクションは多くのメモリリークを防ぐが、リークは、未だにいくらかの状況に置いて可能である。[要出典]
- Javaは簡単に非メモリリソースを漏らすが、慣用的なC++はそれが非常に強い。
ライブラリ
- JavaはC++と比べ随分と巨大な標準ライブラリを持つ。C++標準ライブラリは文字列、コンテナ、I/Oストリームのような比較的一般的な目的のコンポーネントだけを提供する。
Java標準ライブラリはネットワーキング、グラフィカルユーザインタフェース、XML処理、ロギング、データベースアクセス、暗号化やそのか様々な領域のコンポーネントを含む。この追加機能性はC++では(よくフリーで)サードパーティライブラリによって可能になるが、いくつかの実装をみたすに必要ではない。
- C++はたいていCとの後方互換性があり、(多くのオペレーティングシステムのAPIのような)CライブラリはC++から直接書くセスできる。Javaではよりリッチな標準ライブラリの機能性[要出典]が、大抵はプラットフォーム固有ライブラリにである多くの特徴があるものにクロスプラットフォームでアクセスできるものを提供する。
Javaからネイティブなオペレーティングシステムやハードウェア機能に直接アクセスするには、Java Native Interfaceを使用する必要がある。
ランタイム
- C++は通常、マシン語に直接コンパイルされてから、オペレーティングシステムによって直接実行される。Javaは通常バイトコードにコンパイルされてからJava仮想マシン(JVM)が
インタプリタでバイトコードを解釈するかまたはJITがバイトコードをマシンコードにコンパイルして実行される。理論上動的再コンパイルは特にJavaなど、どの言語でも使うことができるが、しかし現在は、両方の言語が動的に再コンパイルすることは稀である。
- 強制によらない表現力のため、C++言語の多くの特徴(e.g. チェックされない配列アクセス、未使用ポインタ、型じゃれ)はコンパイル時または実行時の不適当なオーバーヘッド無しに信頼できるチェックを得られない。関係のあるプログラミングエラーは低レベルバッファオーバフロー、ページフォールト、セグメンテーションフォルトを導いてしまう。Standard Template Libraryがそのようなエラーを避けることを助ける高レベルな(ベクトル、リスト (抽象データ型)、マップのような)抽象概念を提供しようとも、Javaではそのようなエラーは単純に起こすことも、JVMに検出されることも無く、例外によってアプリケーションに報告される。
- Java言語は、配列アクセスの境界チェックを一般的に要求する領域外配列アクセスが起きたとき、明確な振る舞いを要求する。これは通常、実行を送らせる犠牲を払って不安定の源になる可能性があるものを除去する。いくつかのケースではコンパイラ解析が不必要に境界チェックを試し、それを消去する。C++はネイティブな配列の配列外アクセスの振る舞いを要求しない。したがって、ネイティブな配列の境界チェックを要求しない。C++標準ライブラリコレクションはstd::vectorを好む。けれども、随意の配列チェックを提供する。要約すると、Javaの配列は「常に安全で、厳しく強いられる、可能な限り高速」だがC++のネイティブ配列は「常に高速、完全に強制されない、潜在的に危険」ということである。
多方面
- JavaとC++は多くのソースファイルでコードを分割するために異なる技術を使用する。Javaはすべてのプログラム定義でファイル名とパスが影響するパッケージシステムを使用する。Javaでは、コンパイラは実行可能クラスファイルをインポートする。C++はソースファイル間で宣言を分割するヘッダファイルのソースコード包含システムを使用する。(参考 importとincludeの比較。)
- コンパイルされたJavaコードファイルは通常、C++のコードファイルよりも小さい。第一に、Javaバイトコードは通常、ネイティブな機械語よりもコンパクトである [要出典]。第二に、C++にあるテンプレートやマクロは標準ライブラリにそれらを含んでおり、コンパイルの後で結果的に類似コードの重複をもたらしてしまう。第三に標準ライブラリと共に、動的リンクはコンパイル時にライブラリとの結合を消去する。
- C++コンパイルは、Javaにはない、追加された言葉通りのプリプロセッシングのフェーズを特徴づける。このように、ユーザには、条件付きコンパイルの寄りよいサポートのためにビルドプロセスにプリプロセッサを付加する者がいる。
- 双方の言語は、配列が固定サイズである。Javaでは、配列はファーストクラスオブジェクトであるが、C++では配列は配列のベースとなるオブジェクトの連続した領域であり、最初の要素と随意的な配列の長さをポインタを使って参照しているに過ぎない。Javaでは、配列は境界チェックされ、長さもわかっているが、C++ではあなたは配列自体を連続した領域として扱うことができる。C++とJava双方は、リサイズ、サイズ保存できる、コンテナクラス(それぞれ、std::vector と
java.util.Vector
またはjava.util.ArrayList
)提供する。 - Javaの除算と剰余演算子は0を切り捨てるよう正しく定義されている。C++は、これらの演算子が0を切り捨てるか「マイナス無限大に切り捨てる」かを明確に指定しない。 Javaでは、 -3/2 は常に -1 となるだろう。しかし、C++コンパイラは プラットフォームに依存して、-1 を返すかも知れないし -2 を返すかも知れない。C99はJavaと同じ流儀で除算を定義している。双方の言語はすべての a と b (b != 0) で
(a/b)*b + (a%b) == a
を保証する。C++はバージョンによってはときどき、プロセッサにネイティブであるどんな短縮モードもつみ取る高速なものになることがある。 - 整数型のサイズはJavaでは定義されている(intが32ビット、longが64ビット)。しかしC++では整数のサイズやポインタは抑制されたコンパイラ依存となっている。したがって、慎重に書かれたC++コードは32ビットプロセッサ上で絶えずきちんと機能を果たす64ビットプロセッサの能力のアドバンテージを得ることができる。しかしながら、プロセッサの語長に対する懸念無しのC++プログラムは数種のコンパイラできちんと機能を果たすには失敗するかもしれない [要出典]。比べて、Javaの固定された整数のサイズはプログラマが異なる整数型のサイズを懸念する必要が無いことを意味し、プログラムは正確に走らせることができるだろう [要出典]。これは、Javaコードが任意のプロセッサの語長を使って実行させることができなくなって以来、パフォーマンスペナルティを被るかもしれない。
パフォーマンス
このセクションは、 This section compares the relative computing performance of C++ and Java on common operating systems such as Windows and Linux.
Early versions of Java were significantly outperformed by statically compiled languages such as C++. This is because the program statements of these two closely related languages may compile to a few machine instructions with C++, while compiling into several byte codes involving several machine instructions each when interpreted by a Java JVM. For example:
Java/C++ statement | C++ generated code | Java generated byte code |
---|---|---|
vector[i]++; | mov edx,[ebp+4h] mov eax,[ebp+1Ch] |
aload_1 iload_2 |
While this may still be the case for embedded systems because of the requirement for a small footprint, advances in just in time (JIT) compiler technology for long-running server and desktop Java processes has closed the performance gap and in some cases given the performance advantage to Java. In effect, Java byte code is compiled into machine instructions at run time, in a similar manner to C++ static compilation, resulting in similar instruction sequences.
Several studies of mostly numerical benchmarks showing mixed results, argue that Java should be faster than C++ for a number of reasons:[1][2]
- pointers make optimization difficult since they may point to arbitrary data or code
- newly allocated memory is close together because garbage collection compacts memory and allocations are thus sequential in memory; and hence more likely to be 'in the cache'
- run-time compilation can do a better job because it knows what processor it is running on and what code is running - the hot spots
Static compilers can be given hints, using command line switches or pragmas, regarding the processor and other optimization options, but these choices may be wrong for where and when the code is actually run. JIT technology has achieved the next level in compiler evolution; from hints and directives, through optimization based on historic measurement, to optimization using current run-time measurements.
One comprehensive study of microbenchmarks shows quite a large variation in results but indicates that, in general, Java outperforms C++ in operations such as memory allocation and file I/O while C++ outperforms Java in arithmetic and trigonometric operations.[3] For numerical processing, Java has shown significant gains with each new version but still lags C++ and Fortran, in part due to the requirement for reproducibility of floating-point results across all platforms.[4]
参照
- ^ "Performance of Java versus C++" by J.P. Lewis and Ulrich Neuman, USC, Jan. 2003 (updated 2004)
- ^ "Java will be faster than C++" by Kirk Reinholtz, JPL, Apr 2001
- ^ "Microbenchmarking C++, C# and Java" by Thomas Bruckschlegel, Dr. Dobbs, June 17, 2005
- ^ "Java and Numerical Computing" by Ronald F. Boisvert, José Moreira, Michael Philippsen and Roldan Pozo, NIST, Dec 2000
関連項目
外部参考資料
- How Java Differs from C — excerpt from Java in a Nutshell by David Flanagan
- Java vs. C++ resource management comparison - Comprehensive paper with examples
- Why Java Will Always Be Slower than C++ - "Java is high performance. By high performance we mean adequate. By adequate we mean slow." - Mr. Bunny