[解決済み】C#やJavaのGenericsと...C++のTemplatesの違いは?[終了しました]
質問
私は主にJavaを使用しており、ジェネリックは比較的新しいものです。Javaは間違った決定をしたとか、.NETの方が良い実装をしているとか、そういう記事を何度も読みました。
では、ジェネリックスにおけるC++、C#、Javaの主な違いは何でしょうか。それぞれの長所/短所は?
解決方法は?
雑音に声を加えて、一刀両断にする。
C#のジェネリックでは、このような宣言が可能です。
List<Person> foo = new List<Person>();
でないものを置くと、コンパイラが防いでくれます。
Person
をリストに追加します。
裏側では、C#コンパイラはただ単に
List<Person>
を .NET dll ファイルに追加しますが、実行時には、JIT コンパイラが新しいコードセットを構築します。
ListOfPerson
.
この利点は、本当に速くなることです。キャストも何もありませんし、DLLにはこれがListであるという情報が含まれているので
Person
を含んでいることを、後でリフレクションを使用してそれを見る他のコードに伝えることができます。
Person
オブジェクトを作成することができます(そのため、インテリセンスなどを得ることができます)。
この欠点は、古いC# 1.0や1.1のコード(ジェネリックを追加する前のもの)では、これらの新しい
List<something>
そのため、手動で旧来の
List
と相互運用することができます。C#2.0のバイナリコードには後方互換性がないため、これはそれほど大きな問題ではありません。このようなことが起こるのは、古いC# 1.0/1.1のコードをC# 2.0にアップグレードする場合だけです。
Java Genericsでは、このような宣言をすることができます。
ArrayList<Person> foo = new ArrayList<Person>();
表面上は同じに見えますが、実はそうなのです。また、コンパイラは、このように
Person
をリストに入れる。
違いは、舞台裏で何が起こっているかということです。C#とは異なり、Javaは特別な
ListOfPerson
- を使用するだけです。
ArrayList
は、Javaにずっとあるものです。配列から物を取り出すときは、通常の
Person p = (Person)foo.get(1);
キャスティングのダンスが必要です。コンパイラはキーを押す手間を省いてくれますが、スピードヒットやキャスティングはこれまでと同じように発生します。
タイプ・イレイジャー(Type Erasure)とは、このようなことを指します。コンパイラはあなたのためにキャストを挿入し、そして、そのキャストが
Person
だけでなく
Object
この方法の利点は、ジェネリックを理解しない古いコードを気にする必要がないことだ。このコードでは、これまでと同じように
ArrayList
を、これまでと同じように使うことができます。これはJavaの世界ではより重要なことで、Java 5を使ったコードをジェネリックスでコンパイルし、古い1.4以前のJVMで動作させることをサポートしたかったのですが、マイクロソフトは意図的にそれをしないことにしたのです。
デメリットは、前述したスピードの低下と、(1)(2)(3)がないことです。
ListOfPerson
擬似クラスやそのようなものが.classファイルに入っていると、後でそれを見るコード(リフレクションを使ったり、他のコレクションからそれを取り出して、それが
Object
だけを含むリストであることを意味するものであることは、何ら見分けがつきません。
Person
であり、他の配列リストとは異なる。
C++のテンプレートでは、以下のような宣言が可能です。
std::list<Person>* foo = new std::list<Person>();
見た目はC#とJavaのジェネリックのようで、思ったとおりに動いてくれますが、裏では違うことが起きているのです。
C#のジェネリックと最も共通するのは、特殊な
pseudo-classes
javaのように型情報を捨ててしまうのではなく、全く別の魚の缶詰のようなものです。
C#とJavaはどちらも仮想マシン用に設計されたアウトプットを生成します。もし、あるコードを書いて
Person
クラスに関する情報は、どちらの場合でも
Person
クラスは .dll または .class ファイルに格納され、JVM/CLR はこれを使用して処理を実行します。
C++は生のx86バイナリコードを生成します。すべてが
ではない
を知る必要のある仮想マシンは存在しません。
Person
クラスです。ボックス化もアンボックス化もなく、関数はクラスにも何にも属する必要はないのです。
このため、C++コンパイラはテンプレートを使ってできることに何の制限も設けていません。基本的に、手動で書けるコードはすべてテンプレートに書かせることができます。
最もわかりやすい例は、モノを追加することです。
C#とJavaでは、ジェネリックシステムはクラスで利用可能なメソッドを知る必要があり、これを仮想マシンに渡す必要があります。これを伝えるには、実際のクラスをハードコードするか、インターフェイスを使用するしかありません。例えば
string addNames<T>( T first, T second ) { return first.Name() + second.Name(); }
このコードは、C# や Java ではコンパイルできません。
T
というメソッドを提供しています。C#の場合はこのように教えてあげないといけません。
interface IHasName{ string Name(); };
string addNames<T>( T first, T second ) where T : IHasName { .... }
そして、addNamesに渡すものがIHasNameインターフェイスを実装しているかどうかなどを確認する必要があります。javaの構文は異なりますが(
<T extends IHasName>
) が、同じ問題に悩まされています。
この問題の「古典的」なケースは、次のような関数を書こうとすることです。
string addNames<T>( T first, T second ) { return first + second; }
でインターフェイスを宣言する方法はないので、実際にはこのコードは書けません。
+
メソッドが含まれています。失敗です。
C++はこれらの問題を全く抱えていません。コンパイラはVMに型を渡すことを気にしません。もし両方のオブジェクトが.Name()関数を持っていれば、コンパイルされます。もし、両方のオブジェクトに.Name()関数があれば、コンパイルできます。単純なことです。
というわけで、これで完成です :-)
関連
-
[解決済み】パディングが無効で、削除できない?
-
[解決済み】なぜこのコードはInvalidOperationExceptionを投げるのですか?
-
[解決済み】Unityでゲームオブジェクトのすべての子をループスルーして破壊する方法?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] JavaにおけるHashMapとHashtableの違いは何ですか?
-
[解決済み] Javaにおけるpublic、protected、package-private、privateの違いは何ですか?
-
[解決済み] C#の正しいバージョン番号を教えてください。
-
[解決済み] なぜテンプレートはヘッダーファイルでしか実装できないのですか?
-
[解決済み] C++11の'typedef'と'using'の違いは何ですか?
-
[解決済み】C/C++の"-->"演算子とは何ですか?
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】C#で四捨五入する方法
-
[解決済み] 保護レベルによりアクセス不能になりました。
-
[解決済み】C#はJavaのcharAt()と同等?)
-
[解決済み】値が期待した範囲に収まらない
-
[解決済み] 'IEnumerable<SelectListItem>' 型の ViewData アイテムで、キーが国であるものは存在しない。
-
[解決済み】C#のequal to演算子でtextとvarcharのデータ型は互換性がない
-
[解決済み】ファイルやアセンブリ、またはその依存関係の1つをロードできませんでした。
-
[解決済み】JavaでClass<T>を使用するには?
-
[解決済み】C++のSTLはなぜテンプレートに大きく依存しているのですか?(そして*インターフェイス*にはない)
-
[解決済み] C++とJavaの「汎用」型の違いは何ですか?