Java 和 C# 中的基元类型是否不同?

2022-09-03 18:32:21

我正在手动将代码从Java转换为C#,并努力处理(我称之为)基元类型(例如,请参阅自动装箱和取消装箱在Java和C#中的行为是否不同)。从答案中,我了解到(C#)和(C#)是等效的,(C#)也可以在容器中使用,例如作为字典中的键。但是,(Java)不能在像HashMap这样的容器中使用,这就是为什么它被自动装箱到(Java)。。doubleDoubledoubledoubleDouble

  1. (C#) 是基元还是对象?double
  2. 如果它是一个原始的,那么是什么让它的行为与(Java)不同?double

double(C#) 不能设置为 null,除非将其设为 。nullable

  1. (C#) 是否等同于 (Java)?它们都被称为对象吗?double?Double

(在本次讨论中,术语“一等对象”的使用是否有用?


答案 1

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

但是,在此之后,C#和Java往往会分开。

Java为所有基元类型(这是Java中的一个小有限集)提供了包装器类类型,这允许将它们视为对象。等。这些包装器类型是引用类型(读取:类),因此是分配给此类类型化表达式/变量的有效值。最新版本的Java(1.5 / 5 +)添加了从基元到其相应包装器的隐式强制。double/Doubleint/Integerbool/Booleannull

// 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<T> 包装器类型来处理“可为 null 的值类型”。此外,与 Java 一样,C# 具有从值类型到 的隐式转换,但限制 T 本身“不是可为 null 的类型”。TNullable<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是一种值类型,在某些情况下确实允许它具有更紧凑的内存占用量,因为它可以避免引用类型的内存开销:Nullable<T>的内存占用量是多少。但是,它仍然需要比不可 Null 类型更多的内存,因为它必须记住该值是否为 null。根据对齐问题和 VM 实现,这可能明显小于“完整”对象,也可能不明显小于“完整”对象。此外,由于 C#/CLR 中的值已重新确定,因此请考虑必须执行的任何提升操作:

// C#
object x = null;
x = (bool?)true;
(x as bool?).Value // true

文章 Java 提示 130:您知道您的数据大小吗?讨论了引用类型的内存消耗(在 Java 中)。需要注意的一点是,JVM 内部有专门的 Arrays 版本,每个基元类型和对象都有一个(但是,请注意,本文包含一些误导性陈述)。请注意对象(与基元相比)如何产生额外的内存开销和字节对齐问题。但是,C#可以扩展类型的优化数组情况,而不是JVM的有限特殊情况,因为本身只是一种结构类型(或“原语”)。Nullable<T>Nullable<T>

但是,对象只需要很小的固定大小即可在可变槽中保持对它的“引用”。另一方面,类型的可变插槽必须具有空间(插槽本身可能在堆上)。请参见 C# 概念:值与引用类型。请注意,在上面的“提升”示例中,变量的类型为:是 C# 中的“根类型”(引用类型和值类型的父级),而不是专用值类型。Nullable<LargeStruct>LargeStruct+Nullableobjectobject


1 C# 语言支持一组固定的基元/公共类型的别名,这些别名允许访问“友好小写”类型名称。例如,是 的别名,并且是 的别名。除非在作用域中导入了不同的类型,并且将在 C# 中引用相同的类型。我建议使用别名,除非有理由这样做。doubleSystem.DoubleintSystem.Int32DoubledoubleDouble


答案 2

Nullable<double>(aka )在C#中与Java中的a不同double?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的原语,使用值语义。您可以使用关键字创建新的值类型。C# 具有针对所有值类型的自动装箱/取消装箱功能,并且还使所有值类型派生自 。structObject

因此,您可以使用值类型(如),其中您将使用任何对象引用(例如,作为a中的键),如有必要,它将被框住,或者只是直接使用。(C# 的泛型实现足以避免在大多数情况下使用装箱。doubleDictionary