Java和C#中的原始类型是不同的吗?

时间:2009-10-21 00:00:20

标签: c# java primitive first-class

我手动将代码从Java转换为C#并与(我称之为)原始类型(例如,Do autoboxing and unboxing behave differently in Java and C#)进行斗争。根据答案,我了解double(C#)和Double(C#)是等效的,double(C#)也可用于容器,例如作为词典中的一个关键词。但是,double(Java)不能在像HashMap这样的容器中使用,这就是它被自动装箱到Double(Java)的原因。

  1. double(C#)是原语还是对象?
  2. 如果它是一个原始因素,它使它的行为与double(Java)不同?
  3. double(C#)除非设为nullable,否则不能设置为null。

    1. double?(C#)是否等同于Double(Java)?它们都被称为物体吗?
    2. (在这个讨论中,“第一类对象”一词的用法是否有用?)

3 个答案:

答案 0 :(得分:17)

C#和Java都有原始(或“值”)类型:int,double,float等......

然而,在此之后,C#和Java倾向于分裂。

Java为所有基本类型(它是Java中的一个小型有限集)提供了包装类类型,允许将它们视为对象。 double/Doubleint/Integerbool/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#具有从值类型TNullable<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。请注意,在上面的“提升”示例中,变量的类型为objectobject是C#中的“根类型”(两种引用类型和值类型的父类),而不是专门的值类型。


1 C#语言支持一组固定的别名,用于原始/公共类型,允许访问“友好的小写”类型名称。例如,doubleSystem.Double的别名,intSystem.Int32的别名。除非在范围中导入了不同的Double类型,否则doubleDouble将引用C#中的相同类型。我建议使用别名,除非有理由不这样做。

答案 1 :(得分:10)

C#中的{p> 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等,以及“引用类型” - 类等。