我手动将代码从Java转换为C#并与(我称之为)原始类型(例如,Do autoboxing and unboxing behave differently in Java and C#)进行斗争。根据答案,我了解double
(C#)和Double
(C#)是等效的,double
(C#)也可用于容器,例如作为词典中的一个关键词。但是,double
(Java)不能在像HashMap这样的容器中使用,这就是它被自动装箱到Double
(Java)的原因。
double
(C#)是原语还是对象? double
(Java)不同? double
(C#)除非设为nullable
,否则不能设置为null。
double?
(C#)是否等同于Double
(Java)?它们都被称为物体吗? (在这个讨论中,“第一类对象”一词的用法是否有用?)
答案 0 :(得分:17)
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#通过structures支持无限的值类型集;相反,C#通过引入Nullable<T>
包装器类型来处理“可空值类型”。此外,与Java一样,C#具有从值类型T
到Nullable<T>
的隐式转换,并且限制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是一个值类型确实允许它在某些情况下具有更紧凑的内存占用 ,因为它可以避免引用类型的内存开销:What is the memory footprint of a Nullable<T>。但是它仍然需要比非Nullable类型更多的内存,因为它必须记住该值是否为null。根据对齐问题和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中)。需要注意的一点是,JVM内部有专门的Arrays版本,每个基本类型和对象都有一个(但请注意,本文包含一些误导性语句)。请注意对象(与原语相比)如何产生额外的内存开销和字节对齐问题。但是,C#可以扩展Nullable<T>
类型的优化数组大小写与JVM所具有的有限特殊情况相比,因为Nullable<T>
本身只是一种结构类型(或“原始”)。
但是,一个Object只需要一个小的固定大小来在变量槽中维护它的“引用”。另一方面,类型为Nullable<LargeStruct>
的变量槽必须具有LargeStruct+Nullable
的空间(槽本身可能在堆上)。见C# Concepts: Value vs Reference Types。请注意,在上面的“提升”示例中,变量的类型为object
:object
是C#中的“根类型”(两种引用类型和值类型的父类),而不是专门的值类型。
1 C#语言支持一组固定的别名,用于原始/公共类型,允许访问“友好的小写”类型名称。例如,double
是System.Double
的别名,int
是System.Int32
的别名。除非在范围中导入了不同的Double
类型,否则double
和Double
将引用C#中的相同类型。我建议使用别名,除非有理由不这样做。
答案 1 :(得分:10)
Nullable<double>
(又名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称之为value types)。这些行为大多类似于Java的原语,使用值语义。您可以使用struct
关键字创建新的值类型。 C#为所有值类型提供了自动装箱/取消装箱功能,并且还使所有值类型都来自Object
。
所以你可以使用一个值类型(比如double
)来使用任何对象引用(例如作为Dictionary
中的一个键),如果需要,它将被装箱,或者只是使用它直。 (在大多数情况下,C#的Generics实现足以避免装箱。)
答案 2 :(得分:1)
在C#中,分离对象的最佳方法是使用“值类型”,它类似于原语 - int
s,bool
s等,以及“引用类型” - 类等。