C# と Java の両方にプリミティブ (または「値」) 型があります: int、double、float など...
ただし、この後、C# と Java は分裂する傾向にあります。
Java には、すべてのプリミティブ型(Java では小さな有限集合)
のラッパー クラス型があり、それらをオブジェクトとして扱うことができます。double/Double
、int/Integer
、bool/Boolean
など。これらのラッパー型は参照型 (読み: クラス) であり、そのnull
ような型付き式/変数に割り当てる有効な値です。Java の最近のバージョン (1.5/5+) では、プリミティブから対応するラッパーへの暗黙的な強制が追加されています。
// Java
Boolean b = true; // implicit conversion boolean -> Boolean (Java 5+)
Boolean b = null; // okay, can assign null to a reference type
boolean n = null; // WRONG - null is not a boolean!
C# はこのような直接ラッピングを提供しません1 - 一部には、C# が構造体を介して値の型の無限のセットをサポートするためです。むしろ、C# はラッパー型の導入によって "null 許容値型" を処理します。さらに、C# は Java と同様に、値型から への暗黙的な変換を行いますが、T 自体は「null 許容型ではない」という制限があります。Nullable<T>
T
Nullable<T>
// C#
Nullable<bool> b = true; // implicit conversion bool -> bool?
bool? b = true; // short type syntax, implicit conversion
bool? b = null; // okay, can assign null as a Nullable-type
bool b = null; // WRONG - null is not a bool
Nullable<T>
も値型であるため、値が「スタック上」にあるかどうかについては、標準の構造規則に従うことに注意してください。
コメントに応じて:
Nullable が値型であると、参照型のメモリ オーバーヘッドを回避できるため、特定のケースではよりコンパクトなメモリ フットプリントを持つことができます。ただし、値がnullかどうかを覚えておく必要があるため、Nullableでない型よりも多くのメモリが必要です。アラインメントの問題と VM の実装に応じて、これは「完全な」オブジェクトよりも大幅に小さい場合とそうでない場合があります。また、C#/CLR の値は具体化されているため、実行する必要があるリフティング操作を検討してください。
// C#
object x = null;
x = (bool?)true;
(x as bool?).Value // true
記事Java Tip 130: Do you know your data size? 参照型のメモリ消費について (Java で) 話します。注意すべきことの 1 つは、JVM には、各プリミティブ型とオブジェクト用に 1 つずつ、内部的に特殊化されたバージョンの配列があることです (ただし、この記事には誤解を招く記述が含まれていることに注意してください)。オブジェクト (対プリミティブ) が余分なメモリ オーバーヘッドとバイト アラインメントの問題をどのように発生させるかに注意してください。ただし、C# は、型の最適化された配列のケースと、それ自体が単なる構造型 (または「プリミティブ」) であるNullable<T>
ため、JVM が持つ限られた特殊なケースを拡張できます。Nullable<T>
ただし、オブジェクトは、可変スロットで「参照」を維持するために小さな固定サイズしか必要としません。Nullable<LargeStruct>
一方、タイプの可変スロットには、 LargeStruct+Nullable
(スロット自体がヒープ上にある場合もあります) ためのスペースが必要です。C# の概念: 値と参照型を参照してください。上記の「リフティング」の例で変数の型がどのようになっているかに注意してくださいobject
:object
は C# の「ルート型」(参照型と値型の両方の親) であり、特殊な値型ではありません。
1 C# 言語は、 「使いやすい小文字」の型名へのアクセスを許可するプリミティブ/共通型のエイリアスの固定セットをサポートしています。たとえば、double
は のエイリアスでSystem.Double
あり、int
は のエイリアスですSystem.Int32
。Double
別の型がスコープにインポートされてdouble
いない限り、Double
C# で同じ型を参照します。特に理由がない限り、エイリアスを使用することをお勧めします。