Java和C#中的原始类型是否不同?
我手动将代码从Java转换为C#并与(我称之为)原始类型进行斗争(例如,参见自动装箱和拆箱在Java和C#中表现不同 )。 从答案中我理解double
(C#)和Double
(C#)是等价的, double
(C#)也可以用在容器中,例如作为Dictionary中的键。 但是, double
(Java)不能在像HashMap这样的容器中使用,这就是它被自动装箱到Double
(Java)的原因。
-
double
(C#)是一个原语还是一个对象? - 如果它是一个原始的,它使它的行为与
double
(Java)不同?
double
(C#)除非可以为空,否则不能设置为null。
-
double?
(C#)相当于Double
(Java)? 它们都被称为物体吗?
(在这次讨论中,“第一类对象”一词的用法是否有用?)
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#通过引入Nullable
包装器类型来处理“可空值类型”。 此外,与Java一样,C#具有从值类型T
到Nullable
隐式转换,其限制是T本身“不是可空类型”。
// C# Nullable 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
也是一个值类型,因此遵循标准结构规则,用于何时/如果值是“在堆栈上”或不是。
回应评论:
绝对正确,Nullable是一个值类型确实允许它在某些情况下具有更紧凑的内存占用,因为它可以避免引用类型的内存开销: Nullable
// C# object x = null; x = (bool?)true; (x as bool?).Value // true
文章Java技巧130:你知道你的数据大小吗? 讨论引用类型内存消耗(在Java中)。 需要注意的一点是,JVM内部有专门的Arrays版本,每个基本类型和对象一个(但请注意,本文包含一些误导性的陈述 )。 注意对象(与原语相比)如何产生额外的内存开销和字节对齐问题。 但是,C#可以扩展Nullable
类型的优化数组的情况,而不是JVM所具有的特殊情况,因为Nullable
本身只是一种结构类型(或“原始”)。
但是,一个Object只需要一个小的固定大小来在变量槽中维护它的“引用”。 另一方面, Nullable
类型的变量槽必须具有LargeStruct+Nullable
空间(槽本身可能在堆上)。 请参阅C#概念:值与参考类型 。 请注意,在上面的“提升”示例中,变量的类型是object
: object
是C#中的“根类型”(两种引用类型和值类型的父类),而不是特殊的值类型。
1 C#语言支持原始/公共类型的一组固定别名 ,允许访问“友好的小写”类型名称。 例如, double
是System.Double
的别名, int
是System.Int32
的别名。 除非在范围内导入不同的Double
类型,否则double
和Double
将引用C#中的相同类型。 除非有理由不这样做,否则我建议使用别名。
C#中的Nullable
(又名double?
)与Java中的Double
。
在Java进行自动装箱/拆箱之前,您必须手动转换基元和第一类对象:
Double dblObj = new Double(2.0); double dblPrim = dblObj.doubleValue();
在Java 1.5中发生了变化,所以你可以这样做:
Double dblObj = 2.0; double dblPrim = dblObj;
Java会自动插入代码来镜像上面的例子。
C#是不同的,因为有无限数量的“原始”类型(CLR称之为值类型 )。 这些行为大多类似于Java的原语,使用值语义 。 您可以使用struct
关键字创建新的值类型。 C#对所有值类型都有自动装箱/取消装箱,并且还使所有值类型都来自Object
。
因此,您可以使用值类型(如double
),您可以使用任何对象引用(例如,作为Dictionary
的键),如果需要,它将被装箱,或者直接使用。 (在大多数情况下,C#的Generics实现足以避免装箱。)
在C#中,分离对象的最佳方法是“值类型”,它有点像基元 – int
s, bool
s等,“引用类型” – 类等。