【问题标题】: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 是什么时候创建的?什么时候添加到内存中?

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

【问题讨论】:

    标签: c# .net reference-type indirection


    【解决方案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 X{public int i;}
    • 感谢指正。我以为我在某处读到 intInt32 的别名。
    • @Samuel int Int32 的别名。但是Int32是值类型,和Java的Integer完全不同。
    猜你喜欢
    • 1970-01-01
    • 2018-08-08
    • 1970-01-01
    • 1970-01-01
    • 2021-06-18
    • 1970-01-01
    • 2018-06-10
    • 1970-01-01
    • 2020-02-15
    相关资源
    最近更新 更多