声明和实例化一个 c# 数组实际上是啥意思?

Posted

技术标签:

【中文标题】声明和实例化一个 c# 数组实际上是啥意思?【英文标题】:What does declaring and instantiating a c# array actually mean?声明和实例化一个 c# 数组实际上是什么意思? 【发布时间】:2013-07-09 16:03:41 【问题描述】:

我正在阅读 c# 数组,所以我的问题最初是关于数组的。

声明一个数组实际上意味着什么?我知道你声明了一个数组类型的变量。当我有以下情况时,实际发生了什么?

int[] values;

它在声明时是否在内存中?如果不是,那么它在哪里?数组真的是在这里创建的吗?

然后我去实例化一个数组并用一些值初始化它:

int[] values = new int[]  1, 2, 3 ;

现在真的要创建数组了吗?我读过数组是在声明时创建的,其他人说数组是在实例化时创建的。我正在尝试正确使用我的术语。

整数变量也是如此。如果我有:

int value;

int value = 1;

int 是什么时候创建的?什么时候添加到内存中?

对不起,愚蠢的问题。我理解这个概念,但想知道数组背后的技术。

【问题讨论】:

【参考方案1】:

声明一个数组究竟意味着什么?

你实际上并没有声明一个数组,你声明了一个数组reference。在 .NET 中很重要,引用类型和值类型之间的区别很重要。仅仅拥有数组引用变量是不够的,还需要一个额外的步骤来创建 数组对象。这需要 new 关键字。它在存储引用类型对象的地方,即垃圾收集堆中为数组对象物理分配存储空间。

整数变量也是如此

不,差别很大。那是一种价值类型。如果它不是类的字段,从您的问题中不清楚,那么它是方法的局部变量。它在方法开始运行时创建,并在方法返回时消失。高度优化,值类型存在于 C# 中的核心原因。如果方法使用过多的局部变量,物理存储位置通常是 cpu 寄存器或堆栈帧上的插槽。

如果它实际上是一个类的成员,那么它会在创建类对象时创建。就像数组一样,在 GC 堆上使用 new 关键字。

【讨论】:

如果从字面上理解,new关键字不是创建数组对象所必需的,也可以写成int[] values = 1, 2, 3 ;之类的东西。尽管您可以认为这只是使用 new 的完整语法的快捷方式。 @Hans:声明数组引用会占用内存吗?还是仅在创建数组时? 确实如此,指针的大小。 32 位进程中 4 个字节,64 位进程中 8 个字节。引用的存储遵循与值类型值相同的规则。【参考方案2】:

当你这样声明时:

int[] values;

您没有指定大小,因此无法知道实例化需要多少内存。此信息仅在以下行中给出:

values = new int[]  1, 2, 3 ;

内存需求是从实例化值的数量推导出来的(当然还有int 类型的内存需求)。

当你像这样声明一个 int 时:

int value;

内存要求是已知的并且不能改变(因为int 是一个值类型)。该变量可以(并且将)立即创建。如果您不指定初始值,它将具有默认值,对于int,默认值为0

【讨论】:

你是说如果你只写int[] values,那么那个变量的内存就没有分配?这是错误的,因为该变量包含一个引用,并且为该 分配了内存 另外,谈论局部变量的默认值是没有意义的,它们没有。比如你不能写int i; Console.WriteLine(i); @svick:您的评论编号 1:我表达得不够清楚,我的意思是未分配 数组 的内存。您的评论编号 2:int,与所有值类型一样,具有默认值。 C# 编译器不允许您使用以前未初始化的变量 you,这是正确的。但是您示例中的 i自动初始化为其默认值,即 0。例如,您可以在调试器中进行检查。将Console.WriteLine(i);替换为Console.WriteLine("bla");,在该行设置断点并检查i,你会看到它的值为0。 不过,如果你不能访问它,谈论默认值是没有意义的。你确定你会在启用所有优化的调试器中得到相同的行为吗? @svick:我不确定,但我相信必须在使用前初始化 是 C# 特定的功能,而不是 CLI 强制执行的功能。所以我希望行为与优化相同。您对默认值实际上无关紧要是正确的。但是由于这里的大多数答案都是“头发分裂模式”,我认为具有默认值的细节在这里;-)【参考方案3】:
int[] values;

意味着您声明了一个 int[] 类型的变量。还没有占用内存,只创建了一个引用。上面的代码被初始化为一个空引用。

int[] values = new int[]  1, 2, 3 ;

此代码声明了一个 int[] 类型的变量,并立即创建了一个数组。该变量引用了新创建的数组。

整数的工作方式略有不同,因为它们是值类型。值类型被初始化为其默认值,如果是整数,则值为 0。

如果将声明和初始化分开,会发生以下情况。

// This declares a variable
int[] values;
// This creates the array, and initializes the variable with the newly created array.
values = new int[]  1, 2, 3 ;

【讨论】:

只有当int[] 是某个类型的成员并且创建该类型的实例时,才能为它创建一个空引用。如果你在一个方法中这样做,在你初始化它之前你甚至没有引用。 @Renan 我不确定你的意思。空引用不是任何类型的成员 (ericlippert.com/2013/05/30/what-the-meaning-of-is-is)。 “还没有占用内存,只创建了一个引用。”你是说引用不占用任何内存? @Maarten 我认为 Renan 是想说你不能做 int[] values; Console.Write(values);。你不能访问未初始化的局部变量,所以谈论它的默认值是没有意义的。 @svick 不,我的意思是对象(在本例中为整数数组)尚未创建。引用本身(在本例中为空引用)已创建,并且确实占用了内存(我认为引用是 32 位系统上的 Int32)。【参考方案4】:

当您声明一个数组时,在内部创建的只是一个int[] 类型的空指针。当您在示例中使用 new 关键字或使用 new int[6] 时,系统会为数组的大小分配内存。

声明int实际上会为默认值为0的整数创建内存。

【讨论】:

C# 的行为相同,因为int 是一种值类型,请参见此处:msdn.microsoft.com/en-us/library/s1ax56ch.aspx。 Quote: 与引用类型不同,值类型不能包含空值。 (...) 每个值类型都有一个隐式默认构造函数,用于初始化该类型的默认值。 您的第二段不正确。 int 是默认为零的值类型。试试这个:void Main()Console.WriteLine(new X().i);class Xpublic int i; 感谢指正。我以为我在某处读到 intInt32 的别名。 @Samuel int Int32 的别名。但是Int32是值类型,和Java的Integer完全不同。

以上是关于声明和实例化一个 c# 数组实际上是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章

实例化类对象是啥意思?

java中实例化方法是啥意思

JAVA的“一个类只能要求有一个实例化对象”是啥意思

在 C# 中实例化一个数组 - 从 VB 转换 [重复]

用c++设计一个类,该类仅仅被允许实例化一次! 这题目是啥意思?求解

在c++中,接口能实例化吗?下面是接口实例化吗?operFactory是啥?我初学。