Java 和 C# 中的基本类型有何不同?

发布于 2024-08-08 04:56:44 字数 675 浏览 11 评论 0原文

我正在手动将代码从 Java 转换为 C#,并与(我所说的)原始类型作斗争(参见,例如 自动装箱和拆箱在 Java 和 C# 中的行为是否不同)。从答案中我了解到 double (C#) 和 Double (C#) 是等效的,并且 double (C#) 也可以在容器中使用,例如作为字典中的键。然而,double (Java) 不能在像 HashMap 这样的容器中使用,这就是它被自动装箱为 Double (Java) 的原因。

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

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

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

(在本次讨论中使用术语“一流对象”有用吗?)

I am manually converting code from Java to C# and struggling with (what I call) primitive types (see, e.g. Do autoboxing and unboxing behave differently in Java and C#). From the answers I understand that double (C#) and Double (C#) are equivalent and double (C#) can also be used in containers, e.g. as a key in a Dictionary. However, double (Java) cannot be used in containers like HashMap which is why it is auto-boxed to Double (Java).

  1. Is double (C#) a primitive or an object?
  2. If it's a primitive what makes it behave differently from double (Java)?

double (C#) cannot be set to null unless it is made nullable.

  1. Is double? (C#) equivalent to Double (Java)? Are they both referred to as objects?

(Is the use of the term "first-class object" useful in this discussion?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

世界等同你 2024-08-15 04:56:44

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# 通过 结构;相反,C# 通过引入 Nullable< 来处理“可空值类型”。 T> 包装类型。此外,与 Java 一样,C# 具有从值类型 TNullable 的隐式转换,但限制是 T 本身“不是可为 null 的类型”。

// 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 也是一种值类型,因此遵循关于值何时/是否“在堆栈上”的标准结构规则。

回应评论:

绝对正确,Nullable 作为值类型确实允许它在某些情况下拥有更紧凑的内存占用,因为它可以避免引用类型: Nullable 的内存占用是多少< /a>.然而,它仍然比非 Nullable 类型需要更多的内存,因为它必须记住该值是否为 null。根据对齐问题和 VM 实现,这可能会或可能不会显着小于“完整”对象。此外,由于 C#/CLR 中的值已具体化,因此请考虑必须执行的任何提升操作:

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

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

然而,一个对象只需要一个小的固定大小来在变量槽中维护对其的“引用”。另一方面,Nullable 类型的变量槽必须具有用于 LargeStruct+Nullable 的空间(槽本身可能位于堆上)。请参阅 C# 概念:值与引用类型。请注意,在上面的“提升”示例中,变量的类型为 objectobject 是 C# 中的“根类型”(引用类型和值类型的父级),并且不是特殊的值类型。


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

Both C# and Java have primitive (or "value") types: int, double, float, etc...

However, after this C# and Java tend to divide.

Java has wrapper Class types for all of the primitive types (which is a small finite set in Java) which allows them to be treated as Object.
double/Double, int/Integer, bool/Boolean, etc. These wrapper types are reference-types (read: Classes) and, as such, null is a valid value to assign to such typed expressions/variables. Recent versions of Java (1.5/5+) add in implicit coercions from primitives to their corresponding wrapper.

// 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# doesn't provide a such a direct wrapping1 - in part, because C# supports an infinite set of value types via structures; rather, C# handles "nullable value types" by introduction of a Nullable<T> wrapper type. In addition C#, like Java, has implicit conversions from the value type T to Nullable<T>, with the restriction that T is "not a nullable type" itself.

// 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

Note that Nullable<T> is also a value type and thus follows the standard structure rules for when/if a value is "on the stack" or not.

In response to the comment:

Absolutely correct, Nullable being a value-type does allow it to have a more compact memory footprint in certain cases as it can avoid the memory overhead of a reference type: What is the memory footprint of a Nullable<T>. However it still requires more memory than the non-Nullable type because it has to remember if the value is, well, null, or not. Depending upon alignment issues and VM implementation, this may or may not be significantly less than a "full" object. Also, since values in C#/CLR are reified, consider any lifting operations that must be performed:

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

The article Java Tip 130: Do you know your data size? talks about reference type memory consumption (in Java). One thing to note is that the JVM has specialized versions of Arrays internally, one for each primitive type and for Objects (however, please note that this article contains some misleading statements). Note how the Objects (vs. primitives) incur extra memory overhead and the byte alignment issues. C# however, can extend the optimized-array case for Nullable<T> types vs. the the limited special-cases the JVM has because Nullable<T> is itself just a structure type (or "primitive").

However, an Object, only requires a small fixed size to maintain a "reference" to it in a variable slot. A variable slot of type Nullable<LargeStruct> on the other hand, must have space for LargeStruct+Nullable (the slot itself may be on the heap). See C# Concepts: Value vs Reference Types. Note how in the "lifting" example above the variable is of type object: object is the "root type" in C# (parent of both reference types and value types) and not a specialized value type.


1 The C# language supports a fixed set of aliases for primitive/common types that allow access to "friendly lowercase" type names. For instance, double is an alias for System.Double and int is an alias for System.Int32. Unless a different Double type is imported in scope, double and Double will refer to the same type in C#. I recommend using the aliases unless there is a reason to do otherwise.

拒绝两难 2024-08-15 04:56:44

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 ),在其中您可以使用任何对象引用(例如作为字典中的键),并且如有必要,它将被装箱,或者否则就直接使用。 (C# 的泛型实现足以在大多数情况下避免装箱。)

Nullable<double> (aka double?) in C# is not the same as a Double in Java.

Before Java had autoboxing/unboxing, you had to manually convert between primitives and first-class objects:

Double dblObj = new Double(2.0);
double dblPrim = dblObj.doubleValue();

In Java 1.5 that changed, so you could just do:

Double dblObj = 2.0;
double dblPrim = dblObj;

And Java would insert code to mirror the above example automatically.

C# is different because there is an unlimited number of "primitive" types (what the CLR calls value types). These behave mostly like Java's primitives, using value semantics. You can create new value types using the struct keyword. C# has autoboxing/unboxing for all value types, and also makes all value types derive from Object.

So you can use a value type (like double) where you would use any object reference (e.g. as a key in a Dictionary) and it will be boxed if necessary, or else just used directly. (C#'s Generics implementation is good enough to avoid boxing in most circumstances.)

源来凯始玺欢你 2024-08-15 04:56:44

在 C# 中,分隔对象的最佳方法是通过“值类型”,它有点像基元 - intbool 等,以及“引用类型” - 类等。

In C#, the best way to separate objects are by "Value Types" which are kinda like primitives - ints, bools, etc and "Reference Types" - classes etc.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文