C#とJavaの比較(シーシャープとジャバのひかく)では、C#とJavaの比較について説明する。いずれの言語もオブジェクト指向言語であり、その文法はC++に類似しているが、C++との互換性はない。メモリ再利用の手段として、従来の手動で解放する方法ではなくガベージコレクションを使用する。また、スレッド同期の手段を言語構文に組み込んでいる。いずれの言語も強い参照と弱い参照の両方をもつ。Javaでは参照がガベージコレクタによって回収された時に通知を受けるリスナーを登録することができる。これはcodice_1の性能を考慮したものである。C#にはこれに相当する機能はなく、ファイナライザ(Javaにも存在する)を使用する方法しかない。その一方、C#は指定したオブジェクトのファイナライザ呼び出しをプログラマが抑止することができる。「世代」の概念をもつガベージコレクション(Javaと.NETいずれにも当てはまる)においてファイナライザの呼び出しは性能に大きな影響を与えるため、またファイナライザはプログラマがオブジェクトを破棄しなかった場合のフェイルセーフであるため、これは非常に有効である。ファイナライザをもつオブジェクトは通常余分な世代が与えられ、回収されるまでに長くかかる。C#は、一部の言語設計者から危険であるとされるポインタを使用した演算が制限つきながら利用できる。C#はポインタを使用するコードブロックあるいはメソッドをcodice_2キーワードで修飾することでこの懸念に対応している。これにより、このコードを利用する者はそれが他の部分に比べて危険であるということを知ることができる。また、このようなコードをコンパイルする際にはコンパイラに対して/unsafeスイッチを指定する必要がある。一般に、unsafeコードが使われるのはアンマネージなAPIやシステムコールとの相互運用が必要な時、あるいは性能の向上が必要な時のみである。いずれの言語もプリミティブ型(C#では値型と呼ばれる)の概念をもつ。C#はそのような型をJavaよりも多くもち、符号つき整数だけでなく符号なし整数もサポートされる。さらに、10の累乗の形で指数部を表す浮動小数点数であるcodice_3型をサポートする。Javaには符号なし整数が存在しない。文字列はいずれの言語においても不変 ()なオブジェクトとして扱われるが、特殊な構築方法として文字列リテラルを利用することができる。C#ではエスケープ文字を処理しないような文字列リテラル(文字列)をサポートする。いずれの言語もプリミティブ型とオブジェクト型の間で変換するためにボックス化とボックス化解除が可能である。これによってプリミティブ型はオブジェクト型のサブセットとみなすことができる。C#においては、これによってプリミティブ型で多態性を利用することが可能である(例えばcodice_4型のcodice_5メソッドをオーバーライドすることができる)。Javaではこのような用途のためにプリミティブ型をラップするクラスが別に定義される。すなわち、codice_6のようなインスタンス呼び出しでなくcodice_1のような静的呼び出しが必要になる。もう一つの相違点として、Javaではジェネリックスにおいてこのような型を多用するため、暗黙的なボックス化解除が可能になっている(C#ではキャストが必要である)。このような変換はnullポインタ例外を発生する可能性があるが、Javaではそれがコード上で明白ではない。C#では、codice_8キーワードによって値型を定義することができる。値型にはフィールドやメソッド、プロパティなどの任意のメンバを定義できる。プログラマの視点からは、これは軽量なクラスとみなせる。値型は通常のクラスと異なり、そして組み込みのプリミティブ型と同様、ヒープ領域ではなくスタックに置かれる。また、クラスの一部になる(フィールドとして、あるいはボックス化された状態で)ことも、配列の要素になることも可能である。通常のクラスではメモリ上で間接的に参照される必要があるが、これらはその必要がない。しかし、値型には多数の制限がある。値型は通常nullの値をとることができず、また初期化なしで配列の要素となる必要があることから、常に暗黙のデフォルトコンストラクタが定義される(これはメモリ領域をゼロで初期化する)。プログラマは一つ以上の引数をもつコンストラクタしか定義することができない。また、これは値型は仮想メソッドテーブルを持たないということを意味し、そのため継承関係をもつことができない(インタフェースの実装は可能である)。なお、.NET Framework 2.0でnull許容型が導入され、C#でも擬似的にnull値を取り得る値型が利用可能となった。C#の列挙型は組み込みの整数型をベースとしている。ベースとなる整数型のどの値も列挙型の値として有効になる(明示的なキャストは必要であるが)。このため、ビットフラグにおいてビットごとのOR演算で列挙型の値を組み合わせることが可能である。一方、Javaの列挙型はオブジェクトである。Javaの列挙型として有効な値は定義においてリストされたものだけである。列挙型の値を組み合わせるためには列挙セットクラスを使用する必要がある。Javaの列挙型では、値によって異なるメソッドの実装が可能である。JavaとC#はいずれも列挙型を文字列に変換することができるが、Javaにおいてはこの変換をカスタマイズすることができる。配列やコレクション型は、イテレータによるcodice_9構文をはじめ、いずれの言語の構文においても重視されている。いずれの言語も配列に相当するcodice_10クラスをもつ。C#は真の多次元配列をサポートするが、Javaでは「配列の配列」として表現する必要がある(これはC#ではジャグ配列と呼ばれる)。ジャグ配列では参照の展開が次元の分だけ必要なのに対し、多次元配列ではそれが一回で済むため、これは性能向上に寄与する。またジャグ配列では各次元ごとに初期化のために明示的なループが必要なのに対し、多次元配列では一回のnew演算子の使用で領域が確保できる点も性能に影響する。いずれの言語も内部クラス(クラスの内部に定義されたクラス)を定義できる。Javaでは、内部クラスからは外側のクラスの静的メンバ、非静的メンバいずれにもアクセスすることができる(内部クラスがcodice_11として定義されていた場合は静的メンバのみ)。メソッドの内部にローカルクラスを定義することもでき、ローカル変数には読み込みアクセスのみすることができる。また、匿名ローカルクラスによってそのクラスのメソッドをオーバーライドしたクラスのインスタンスを作成することができる。C#では、外部クラスの非静的メンバにアクセスするためには外部クラスインスタンスへの明示的な参照が必要になる。ローカルクラスは存在せず、その代わり、ローカル変数やメンバにアクセスすることのできる匿名デリゲートがサポートされる。Javaではジェネリクスは型消去 () によって実装されている。これによってジェネリック型についての情報は実行時には失われ、リフレクションを通してのみ取得できるようになる。.NET 2.0では、ジェネリック型についての情報は完全に保存される。Javaはプリミティブ型に対するジェネリック型は定義できないが、C#では参照型・値型(プリミティブ型を含む)いずれに対してもジェネリック型を定義できる。Javaはその代わりにボックス化した型を使用することができる(codice_12の代わりにcodice_13など)が、全ての値をヒープに確保し直す必要があるため、パフォーマンスコストが高い。JavaとC#はいずれも、参照型に特殊化されたジェネリック型は、型によらず共通のコードが実行される。しかし、C#において値型に特殊化された場合、CLRは型に最適化されたコードを動的に生成する。.NETにおいては、ジェネリック型に対する型安全性はコンパイル時にチェックされ、CLRにロードされる時に強制される。Javaにおいてはコンパイル時に部分的にチェックされるのみであり、Java VMは実行時にジェネリック型に関する情報を持たないため、キャスト操作を行う必要がある。Javaはあるクラスの静的メソッド・静的フィールドを短い名前で使用するためにcodice_14構文をもつ(別のクラスのcodice_15メソッドを静的インポートしてcodice_16と記述できる)。C#は静的クラス(Javaの静的内部クラスとは異なる)の構文をもち、これによってクラスは静的メソッドのみを持つことができるようになる。C# 3.0から、型に静的にメソッドを追加するための拡張メソッドが導入されている(codice_17についての処理を行うcodice_18拡張メソッドを追加し、codice_19と記述できる)。この機能は、しばしばオブジェクト指向におけるカプセル化の概念を破壊するものとして誤解されるが、ターゲットとなるクラスのプライベートメンバにアクセスすることは出来ないため、そのような事は無い。Javaでは、プログラマがObserver パターンを記述するために匿名内部クラスという糖衣構文が用意されている。これにより、コードのある点でクラス本体の定義とインスタンスの作成を同時に行うことができる。これはオブザーバを作成するためによく用いられる。C#ではデリゲート型をはじめ、イベント処理をサポートするための機能が広範囲に渡って言語レベルでサポートされている。デリゲート型はメソッドへの型安全な参照であり、複数のものを結合してマルチキャスティングすることもできる。これらをサポートするため、イベントを定義するための構文や、イベントハンドラを登録・登録解除・結合をするための演算子が存在する。デリゲートは共変性と反変性 () をサポートし、完全なクロージャとしての性質をもつ匿名メソッドを作成することができる。数学・金融分野のアプリケーションの作成に十分対応するため、言語仕様が互いに存在する。Javaでは厳密な浮動小数点計算を強制するためにcodice_20キーワードが存在する。これによってあらゆるプラットフォームで必ず同じ値が結果として得られることを保証することができる。C#にはこれに相当する機能はないが、厳密な浮動小数点計算のためにcodice_3型が存在する。これによって二進浮動小数点表現(codice_22、codice_23)に存在した問題が解決される。これら二進表現は十進数を正確に表現することができないため、丸め誤差が生じてしまっていた。金融分野のアプリケーションソフトウェアでは厳密な十進表現は必須である。Javaでは、このような用途のためにcodice_1が導入されている。codice_25とcodice_1は最大で約21億桁程度までの数を任意精度で表現できる。C#においては、.NET Framework4よりBigInteger型が導入されている。また、第三者による実装も存在する。Javaでは、codice_25や複素数型といったライブラリ定義の型をプリミティブ型と同じレベルで使用することは不可能である。一方、C#は次のような機能をサポートする。これらに加え、C#では数値処理アプリケーションのために、コード中のある領域の数値オーバーフローの実行時チェックを有効・無効にするためにcodice_30・codice_31キーワードが使用できる。C#は表記法の多くの点でJavaよりも多機能である。演算子多重定義やユーザ定義キャストなど、それらの多くはC++プログラマによって既に親しまれているものである。また、明示的メンバ実装 (Explicit Member Implementation)が可能である。これによって、インタフェースメソッドの実装とクラス自身のメソッドの実装とを分離することができ、また同じ名前とシグネチャをもつメソッドが異なるインターフェースに存在した場合に、それらの実装を別々に行うことができる。C#はインデクサ(C++のcodice_32に相当)をサポートする。インデクサはcodice_33という名前をもち、一つ以上の引数(インデックス)をもつプロパティである。インデックスはあらゆる型をとることができる。Javaは、乱用を防ぐため演算子オーバーロードをサポートせず、言語仕様をシンプルにしている。C#は論理的一貫性を保つための制限はあるものの演算子オーバーロードをサポートしており、注意深く使用すれば簡潔で可読性の高いコードを記述することができる。C#のメソッドはデフォルトだと非仮想的(非)であり、必要ならば明示的にcodice_34と宣言しなければならない。Javaのメソッドのデフォルトは仮想的(C#でvirtual指定された状態)であり、finalを付けることで逆に非仮想的に近い状態になる。Javaでは、メソッドを非仮想的にする方法はない(codice_35修飾子でオーバーライドを禁止することはできる)。これは、派生クラスが同名の無関係なメソッドを再定義することが不可能であることを意味する。これは基底クラスが別のプログラマによって書かれており、バージョン更新の際に、派生クラスに既に存在していたものと同じ名前・シグネチャのメソッドが追加されてしまった場合に問題になる。Javaでは、この場合どちらのプログラマの意図とも異なり、派生クラスのメソッドは暗黙的に基底クラスのオーバーライドになってしまう(基底クラスでfinal宣言されていた場合はコンパイルエラーになってしまう)。このバージョン更新の問題を避けるため、C#では派生クラスで仮想メソッドをオーバーライドする際には明示的にそのように宣言する必要がある。メソッドが基底クラスのオーバーライドである場合、codice_36修飾子が指定されていなければならない。また、オーバーライドではなく無関係のメソッドを再定義したい場合、codice_37修飾子を指定しなければならない。これらのバージョン更新の問題を部分的に解決するため、Java SE 5.0ではcodice_1アノテーションが導入された。しかし後方互換性のため、この指定は必須ではない。従ってIDEやツールなしに上記のように思いがけずオーバーライドしてしまうような問題を防ぐことはできない。しかし、基底クラスが同じシグネチャのメソッドをもち、正しくオーバーロードされていることを保証することはできる。Javaとは異なり、C#ではプリプロセッサディレクティブを用いた条件コンパイルが実装されている。また、指定されたコンパイル定数が定義されている時のみ呼び出されるようcodice_39属性を指定することができる。この方法によってcodice_40定数が定義されている時のみ評価される表明(アサート)機能 (codice_41)が提供されている。Java 1.4からは実行時に有効・無効が切り替えられるアサート機能が言語仕様として導入されている。C#の名前空間はC++のそれと類似している。Javaのパッケージとは異なり、名前空間はソースファイルの物理的位置とは無関係である。Javaではパッケージ構造とソースファイルの位置が必ずしも一致している必要はないものの、デフォルトではそのような振る舞いをする。Javaではソースファイル名はそのファイルに記述される唯一のクラス名と一致していなければならないが、C#では一つのファイルに複数のクラスを記述することができ、ファイル名に制限はない。C# 2.0からはcodice_42キーワードによってクラスの定義を複数のファイルに分けて記述することが可能になった。Javaは非チェック例外 ()に加えてチェック済み例外 ()をサポートする。C#では非チェック例外のみである。チェック済み例外は、プログラマがメソッドから発生し得るものを全て宣言し、捕捉する必要がある。全てのエラーが処理されることを保証できるため、チェック済み例外は非常に便利だとする者もいる。一方、C#の設計者であるアンダース・ヘルスバーグのように、Javaのチェック済み例外はある程度実験的な仕様であり、小さなプログラムでの例を除いては実装する価値を見出せなかった、とする者もいる。一つの批判として、チェック済み例外はプログラマが空のcatchブロックを記述するのを促進し、codice_43のような危険なコードを増やす結果になってしまったというものがある。また別の批判として、メソッドの実装に変更を加えた結果新しいチェック済み例外が発生するようになる可能性があり、これによって契約が破壊されてしまう、というものがある。これは限られた例外のみが宣言されたインタフェースを実装するメソッドや、メソッドの内部実装が変更された場合に起こり得る。中には、このような予期しない例外が発生することを見越し、あらゆる型の例外が発生し得る、と宣言 (codice_44)するプログラマもいる。これはチェック済み例外の利点を無にしている。しかしながら、いくつかの場面では例外連鎖 ()、すなわち捕捉した例外を別の例外でラップして投げ直す、という手法が適用できる。例えば、ファイルにアクセスするコードがデータベースにアクセスするよう変更された場合、呼び出し側は内部で何が行われているかを知る必要がないため、codice_1が捕捉された場合でもcodice_1として投げ直すことが可能である。codice_47ステートメントにおいても両者は異なる。codice_48は例えcodice_49ブロック内でcodice_50やcodice_51が実行された場合でも必ず実行される。これは、codice_49内とcodice_48内で異なる値がcodice_51された場合に予期しない振る舞いを生じることがある。C#ではcodice_48ブロック内ではcodice_51やcodice_57といった文の実行を禁止している。JNIではJavaコード内で非Javaコードを呼び出すことができる。しかしながら、JNIは呼び出されるコードや型、名前に制限がある。このため、Javaとレガシーコードの間に余分なレイヤーが必要になることがよくある。このレイヤーはJavaではない言語で書かれる必要があり、CやC++がよく用いられる。.NETのプラットフォーム呼び出し(、P/Invoke)はC#からアンマネージコードの呼び出しを可能にする。プログラマはメタデータを通して、引数や戻り値がどのように橋渡し(マーシャリング)されるかを完全に制御することができる。このため、余分なレイヤーは必要にならない。P/Invokeは(Win32やPOSIXなどの)手続き型APIにはほぼ完全にアクセスすることができるが、C++クラスライブラリへの直接的なアクセスはきわめて困難である。C#は通常の型チェックなどのCLRの安全のための機能を無効にし、ポインタ変数を利用することができる。この時、プログラマはコードをcodice_2キーワードでマークする必要がある。JNI、P/Invoke、codice_2コードはどれも同様に「危険な」機能であり、セキュリティホールやアプリケーションの不安定性につながる恐れがある。codice_2コードがP/InvokeやJNIに対して優れている点は、アンマネージコードを呼び出すことなくC#の機能内でタスクを完結できる点である。codice_2コードを含むアセンブリはコンパイル時にそのように明示的に指定する必要がある。これにより、実行環境は危険な可能性があるコードであるということを実行する前に知ることができる。C#には、統合言語クエリの為の拡張されたキーワード群が存在し、ソースコード上でSQL構文に似たクエリを直接記述することが出来る。このキーワード群は構文糖として機能し、決められた拡張メソッド呼び出しに展開される。統合言語クエリの拡張メソッド群は、コレクションに対するさまざまな集合演算が実装されており、このような演算をロジックで記述することなく、簡単に操作することが出来る。また、ラムダ式から式ツリー(Expressionクラス)のインスタンスを生成することが出来るため、この機能を使用してデータベースへのクエリ発行・収集を、タイプセーフ性を失うことなく直接的に行うことが出来る(LINQ to SQL、LINQ to Entitiesなど)。Javaでは、このようなクエリ構文を直接サポートしない。Javaはまったく異なる多くのオペレーティングシステム間で実行できる。またパーソナル・コンピュータに限らず、高度な計算処理を必要とする家電製品や、Blu-ray Discのインタラクティブ技術にもBD-Jとして使用されている。このように数多くのJVM実装が存在する。C#もやはりクロスプラットフォームである。主なプラットフォームはWindowsだが、他のプラットフォームにも実装が存在する。有名なものにMono Projectがある。但し、Microsoftによる実装に比較して、未実装部分が多く利用できるライブラリに大きく制限がある。両言語のプログラミングインタフェース、バイナリ形式、実行環境などは非常に様々な機関によって管理されている。C#はEcmaとISO、JISによって定義されている(文法、実行形式 (CLI)、基本クラスライブラリ)。フレームワークの上に新しく実装されたライブラリの多くはこの標準には含まれない(Windows Forms、ASP.NET、ADO.NETなど)。現在のところ、Javaのどの部分も第三者の標準化団体によって標準化されていない。Javaの商標、ソースコードやその他の素材に関してはSun Microsystemsが無制限の独占的な権利を保持しているが、SunはJava Community Process (JCP)と呼ばれるプロセスに参加し、当事者たちがJavaに関連する技術(言語、ツールからAPIに至るまで)に対する変更を専門家団体や諮問会議を通して提案することを許可している。JCP内の規定では、Javaに対する新しい仕様や変更はSunによる承認が必要であるとされている。JCPは営利寄与者に対しては会費が必要としているが、非営利寄与者や個人は無料で参加できる。
出典:wikipedia
LINEスタンプ制作に興味がある場合は、
下記よりスタンプファクトリーのホームページをご覧ください。