Deep Side of Java〜Java 言語再入門 第1回

C, C++, Java の比較

C, C++, Java の比較

  C C++ Java
オブジェクト指向 ×
多重継承 × あり なし(interface)
例外 setjmp,longjmpで実装 あり あり
friend関数 × あり なし
ガベージコレクタ 自分で書く 自分で書く あり
ポインタ あり あり なし(すべてクラスに統合)
演算子オーバーライド × ×(Stringクラスのみ+を再定義)
マルチスレッド ライブラリを使う ライブラリを使う 言語仕様に含む
デストラクタ × あり GCが一元的に扱う
テンプレート
(汎用型)
× あり なし
J2SDK1.5で追加予定
メソッド定義 × 上書きされるものを virtual で指定 上書きされないものを final で指定
変数サイズ 実装依存 実装依存 規格で決めている
プリプロセッサ cpp cpp なし
構造体・共用体 あり あり なし(クラスに統合)
無所属変数・関数 これだけ 可能 不可
パッケージ × × あり
ライブラリ 豊富 Cのものを流用し、デフォルトでは独自のものは少ない 豊富

C文法との違い(オブジェクト指向関連以外)

  1. 基本型のサイズは規格で固定されている。int = 4byte, short = 2byte, long = 8byte, byte = 1byte など。すべて符号付きである。

  2. 基本型の中に、boolean 型が存在する。if文などで使われる条件判定式の評価結果は、Cでは int 値であるが、Java では boolean型(true と false の2値を取る)であると定義されている。だから、C言語風の0値とそれ以外を判定する条件文はもう許されない。
         C             Java 
    int x;
    if( x ) {           if( x != 0 ){
    
  3. 型キャストや代入について、実行時例外が発生する可能性がある。つまり、代入可能な型であるかどうか、動的にチェックしている。

    クラスの場合「代入可能」とは次のことを意味する。

    基底クラス = 派生クラス;
    この場合はより一般的なクラスに代入することになり、キャストなしに代入可能である。これはコンパイル時に問題がないことをチェックできる。
    派生クラス = 基底クラス;
    この場合には、代入元の基底クラスが実は派生クラスのインスタンスであり、キャストや代入を通じてより一般的なクラスになっているものであるかどうかを動的にチェックする必要がある。
    継承関係にないクラス = クラス;
    これはコンパイル時に代入不可を決定できる。


  4. 暗黙の型変換は警告になる。つまり、型について厳格な姿勢を取る。数値リテラルはちゃんと 5L, 0.3f 3.14d などと修飾するのが望ましい。

  5. 配列はポインタの甘口文法ではなく、独自のオブジェクトである。だから、配列サイズを越える添字アクセスは実行時例外となる。

  6. null がヌルポインタのシンボルだが、これは数値0ではなくて、特殊なプリミティヴ型のリテラル値である。void はCと同じくキーワードである。

  7. 文字列は char配列(あるいはポインタ)ではなく、Stringクラスに属するオブジェクト(やや異例のクラスだが)である。また、内部コードとして UNICODE(だからJava の char 型は 16bit) を使うことになっており、Stringクラスのオブジェクトに文字をセットする時には変換がなされる。

  8. sizeof 演算子はなく、それぞれのクラスの size() メソッドを使う。

  9. instanceof 演算子がある。これはあるインスタンスに代入可能かどうか判定する演算子である。

  10. unsigned 修飾型は存在しない。これは右ビットシフトの時に数値シフトされることになるので、特に論理シフトする演算子 >>> が導入されている。

  11. 定義の入れ子ができ、内部クラスを定義できる。また、それを無名にもできる。たとえば次の通り。
    class GUI extends Frame {
        Button b = new Button();
        b.addActionListener( 
            new ActionAdaptor() {
                public void actionPerformed( ActionEvent e ) {
                        .............
                }
            }
        );
    }
    
  12. 変数定義はブロック先頭のみではなく、どこでも書ける。(乱用は好ましくないが...)

  13. 初期化子はCと違い、コンパイル時に静的に決定される必要はない。つまり、メソッド呼び出し式や変数演算式でさえ書くことができる。

  14. static 修飾子はスコープを管理するのではなくて、クラス変数、クラスメソッド(インスタンスなしにアクセス可能な変数・メソッド)を示すのに使われる。

  15. 非到達文は警告ではなくコンパイルエラーになる。

  16. 式の評価順は厳格に仕様で決められている。とはいえ、Cでコンパイラ依存になるような式評価を書かないに越したことはない。

  17. ラベルcontinue, ラベルbreak がある。

  18. ポインタは存在しないが、インスタンスは感覚的には構造体ポインタである。なので、-> 演算子や & 演算子は廃止されており、すべて(実質上の)ポインタ参照は . 演算子だけで良い。

  19. C言語の printf属関数などで使われた、仮引数の個数を不定とする関数宣言は廃止されている。(J2SDK1.5で不定長引数仕様が追加される予定



copyright by K.Sugiura, 1996-2006