我只是想知道,为什么我们不能只定义这样的东西:
int[] arr = new int[];
arr[0] = 1;
像列表一样,自动调整大小。 我想知道的是为什么这是不可能的,我们需要每次按以下方式设置大小:
int[] arr = new int[1];
arr[0] = 1;
答案 0 :(得分:12)
List<T>
调整大小是基于在需要时在幕后创建新数组。
想想这里的底层实现是什么样的。分配数组时,它会保留一块内存,并且引用有效地直接指向该内存。如果您需要存储的值多于您保留的值,则需要在其他位置分配更多内存...但您无法更改引用以引用该新内存,因为这些引用都是全部在这个地方。 (数组不知道引用它的是什么。)
显而易见的方法是拥有一个间接级别 - 以便初始引用是一个跟踪真实数据存储位置的对象,因此它可以在需要时重新分配至。这正是List<T>
所做的......但它确实意味着有额外的间接水平。这会带来效率上的成本,部分原因在于您可能会在List
对象本身的内存中获得很长的实际数据,这对缓存来说并不好...... 和简单地通过一个额外的间接层本身就有成本。
基本上,如果您想要动态大小的集合,请使用List<T>
- 这就是它的用途。如果您从一开始就知道最终尺寸,并希望从更接近金属的位置获益,那么#34;数组的方面,改为使用它们。
数组是一个相对较低级别的概念 - 如果你想要一个高级抽象,请使用一个......
答案 1 :(得分:7)
因为数组在内存中是连续的,所以在创建内容时必须为其内容分配足够的内存。
假设您有一个包含100个项目的数组。现在你再添加1个,你必须在第100个项目后面声明内存地址。如果该地址已被使用该怎么办?
这就是你无法动态调整数组大小的原因。
答案 2 :(得分:2)
我的猜测是&#39;因为它以这种方式指定&#39; - 这种情况给出了阵列特定的性能特征和优化能力,这是非常需要的。虽然这些优点已经被设计者注意到,并且存在于也使用类似结构(C,C ++,Java - 脚注1)的影响语言中,但他们真的可以将其定义为任何。
例如, List<T>
必须调整内部数组的大小,通常分配比必要更多的内存(除非你碰巧使用的内容与分配的内容一样多)以及创建垃圾。
1.8 of the C# language specification has the following:
数组是一个包含许多变量的数据结构 通过计算索引访问。包含的变量 数组,也称为数组的元素,都是一样的 type,此类型称为数组的元素类型。
数组类型是引用类型,以及数组变量的声明 只需留出空间来引用数组实例。实际 使用new在运行时动态创建数组实例 运营商。 新操作指定新数组的长度 实例,然后在实例的生命周期内修复。 数组元素的索引范围从0到Length - 1 new运算符自动初始化数组的元素 它们的默认值,例如,对于所有数字类型,它都为零 并且对所有引用类型都为null。
此外,任何人都没有提到 - 其他数组边界检查被认为是一个软件工程原理&#39; - 正如在the ECMA 334 Spec中描述他们的设计目标所述:
语言及其实现应该提供支持 软件工程原理,如强类型检查,数组 边界检查,检测使用未初始化变量的尝试, 和自动垃圾收集。软件稳健性,耐用性和 程序员的工作效率很重要。
Footnote 1 - Introduction of C# language spec:
C#(发音为“See Sharp”)是一个简单,现代,面向对象的,而且 类型安全的编程语言。 C#源于C家族 语言和 将立即为C,C ++和Java所熟悉 程序员。 强>
答案 3 :(得分:1)
这是因为数组分配内存,框架需要知道多少。
如果您想要动态调整大小&#39;,请使用List
。
列表实际上包装了一个数组。在当前数组中添加更多项目时,会创建一个新数组(通常为double size),旧项目将移动到新数组。相反,删除也是如此。
答案 4 :(得分:1)
因为数组的大小是定义的静态而不是动态的。
如果你想要一个动态大小的集合,还有其他的,比如你提到的列表,可用。
你可以做的是延迟声明数组的大小:
int[] numbers;
numbers = new int[10];
numbers = new int[20];