声明和实例化一个 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;
感谢指正。我以为我在某处读到 int
是 Int32
的别名。
@Samuel int
是 Int32
的别名。但是Int32
是值类型,和Java的Integer
完全不同。以上是关于声明和实例化一个 c# 数组实际上是啥意思?的主要内容,如果未能解决你的问题,请参考以下文章