C# 中的 数组[]ArrayListList

数组

在 C# 中,数组实际上是对象,而不只是如在 C 和 C++ 中的连续内存的可寻址区域。

属性:

  • 数组可以是一维、多维或交错的。
  • 创建数组实例时,将建立纬度数量和每个纬度的长度。 这些值在实例的生存期内无法更改。
  • 数值数组元素的默认值设置为零,而引用元素设置为 null。
  • 交错数组是数组的数组,因此其元素为引用类型且被初始化为 null。
  • 数组从零开始编制索引:包含 n 元素的数组从 0 索引到 n-1。
  • 数组元素可以是任何类型,其中包括数组类型。
  • 数组类型是从抽象的基类型 Array 派生的引用类型。 所有数组都会实现 IListIEnumerable。 可在 C# 中使用 foreach 迭代数组。 原因是单维数组还实现了 IList<T>IEnumerable<T>
  1. 命名空间: System;

  2. 特点

    内存连续存储;索引速度快;赋值修改元素简单

  3. 缺点

    插入数据麻烦(连续内存,插入后续的元素都需要移动);声明数组需指定长度(长了没用完浪费内存,短了可能不够用);

  4. 分类

    • 单维数组 eg: int[] array = new int[5];
    • 多维数组 eg:
    int[,] array = new int[4, 2]; // 四行两列的二维数组
    int[,,] array3Da = new int[2, 2, 3] {
    { { 1, 2, 3 }, { 4, 5, 6 } },
    { { 7, 8, 9 }, { 10, 11, 12 } }
    }; // 三个维度(2、2 和 3)的数组
    • 交错数组 eg:
    // 声明一个具有三个元素的一维数组,其中每个元素都是一维整数数组
    int[][] jaggedArray = new int[3][]; // 必须初始化的元素后才可使用它
    jaggedArray[0] = new int[5];
    jaggedArray[1] = new int[4];
    jaggedArray[2] = new int[2];
    • 隐式类型的数组

      通常用于查询表达式、匿名类型、对象和集合初始值设定项.
    var a = new[] { 1, 10, 100, 1000 }; // int[]
    var b = new[] { "hello", null, "world" }; // string[]

Array

数组类型([])是从抽象的基类型 Array 派生的引用类型。

Array 类提供一些方法,用于创建、处理、搜索数组并对数组进行排序,从而充当公共语言运行时中所有数组的基类。

Array的用法与数组[]几乎一样,可以看做是数组。在定义的时候需要指定长度。

Array 的 公共静态成员(public static)是线程安全的。但不保证所有实例成员都是线程安全的。

Array.SyncRoot 属性,用于同步对 Array 的访问的对象。

下面的代码示例演示如何使用属性在整个枚举过程中锁定数组 SyncRoot

Array myArray = new int[] { 1, 2, 4 };
lock(myArray.SyncRoot)
{
foreach (Object item in myArray)
Console.WriteLine(item);
}

ArrayList

为了解决数组的一些短板,ArrayList 继承了 IList 接口,提供了数据存储和检索。 ArrayList 对象的大小是按照其中存储的数据来动态扩充与收缩的。在声明 ArrayList 对象时并不需要指定它的长度。

  1. 命名空间: System.Collections;
  2. 特点

    允许插入不同类型的数据(插入object),无需指定长度;只有一个维度
  3. 缺点

    处理数据可能会报类型不匹配的错误;在存储或检索值类型时通常发生装箱和取消装箱操作,性能耗损较大

装箱:就是将值类型的数据打包到引用类型的实例中

拆箱:就是从引用数据中提取值类型

一些方法:

public virtual int Add(object? value);:将对象添加到 ArrayList 的结尾处,返回已添加 valueArrayList 索引

public virtual void Remove (object? obj);:从 ArrayList 中移除特定对象的第一个匹配

ArrayList 是使用 object 数组 实现的,它涉及拆箱和装箱。默认容量 4

public class ArrayList : IList, ICloneable
{
private object?[] _items; // Do not rename (binary serialization)
private int _size; // Do not rename (binary serialization)
private int _version; // Do not rename (binary serialization) private const int _defaultCapacity = 4; // Constructs a ArrayList. The list is initially empty and has a capacity
// of zero. Upon adding the first element to the list the capacity is
// increased to _defaultCapacity, and then increased in multiples of two as required.
public ArrayList()
{
_items = Array.Empty<object>();
} // Constructs a ArrayList with a given initial capacity. The list is
// initially empty, but will have room for the given number of elements
// before any reallocations are required.
//
public ArrayList(int capacity)
{
if (capacity < 0) throw new ArgumentOutOfRangeException(nameof(capacity), SR.Format(SR.ArgumentOutOfRange_MustBeNonNegNum, nameof(capacity))); if (capacity == 0)
_items = Array.Empty<object>();
else
_items = new object[capacity];
}
}

扩容:

ArrayList 在内部有一个存放数据的数组,当新增数据时候,如果该数组有可用,则会将数据放入数组,并将下标向后移动,如果没有足够的数组,则会进行扩容,如果创建的时候没有给定容量,第一次扩容则会使用默认的容量,如果当前有元素,则会扩容至当前容量的两倍。

可以看到扩容 是将原数组的数据拷贝到新创建的数组中

// Adds the given object to the end of this list. The size of the list is
// increased by one. If required, the capacity of the list is doubled
// before adding the new element.
public virtual int Add(object? value)
{
if (_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size] = value;
_version++;
return _size++;
} // Ensures that the capacity of this list is at least the given minimum
// value. If the current capacity of the list is less than min, the
// capacity is increased to twice the current capacity or to min,
// whichever is larger.
private void EnsureCapacity(int min)
{
if (_items.Length < min)
{
int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Length * 2;
// Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newCapacity > Array.MaxLength) newCapacity = Array.MaxLength;
if (newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
} // Gets and sets the capacity of this list. The capacity is the size of
// the internal array used to hold items. When set, the internal
// array of the list is reallocated to the given capacity.
public virtual int Capacity
{
get => _items.Length;
set
{
if (value < _size)
{
throw new ArgumentOutOfRangeException(nameof(value), SR.ArgumentOutOfRange_SmallCapacity);
} // We don't want to update the version number when we change the capacity.
// Some existing applications have dependency on this.
if (value != _items.Length)
{
if (value > 0)
{
object[] newItems = new object[value];
if (_size > 0)
{
Array.Copy(_items, newItems, _size);
}
_items = newItems;
}
else
{
_items = new object[_defaultCapacity];
}
}
}
}

ArrayList源码

List

通过使用大小根据需要动态增加的数组来实现泛型接口。

相比于ArrayListList<T>不存在装箱拆箱的缺点,List类是ArrayList类的泛型等效类,它的大部分用法都与ArrayList相似,因为List类也继承了IList接口。最关键的区别在于,在声明List集合时,需要为其声明List集合内数据的对象类型。

  1. 命名空间 System.Collections.Generic
  2. 特点

    插入类型固定(泛型);无需指定长度,只有一个维度,允许重复元素

List底层实现使用 泛型数组(Array),默认容量 4,初始化时候可以指定初始化容量,如果不指定则会给定一个空的泛型数组。

public class List<T>:IList<T>,IList,IReadOnlyList<T>
{
private const int DefaultCapacity = 4;
internal T[] _items;
internal int _size;
private int _version; public List()
{
_items = s_emptyArray;
} public List(int capacity)
{
if (capacity < 0)
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.capacity, ExceptionResource.ArgumentOutOfRange_NeedNonNegNum); if (capacity == 0)
_items = s_emptyArray;
else
_items = new T[capacity];
}
}

扩容: List 在内部有一个存放数据的数组,当新增数据时候,如果该数组有可用,则会将数据放入数组,并将下标向后移动,如果没有足够的数组,则会进行扩容,如果创建的时候没有给定容量,第一次扩容则会使用默认的容量,如果当前有元素,则会扩容至当前容量的两倍。

可以看到扩容 是将原数组的数据拷贝到新创建的数组中

[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Add(T item)
{
_version++;
T[] array = _items;
int size = _size;
if ((uint)size < (uint)array.Length)
{
_size = size + 1;
array[size] = item;
}
else
{
AddWithResize(item);
}
} // Non-inline from List.Add to improve its code quality as uncommon path
[MethodImpl(MethodImplOptions.NoInlining)]
private void AddWithResize(T item)
{
Debug.Assert(_size == _items.Length);
int size = _size;
Grow(size + 1); // 扩容
_size = size + 1;
_items[size] = item;
} private void Grow(int capacity)
{
Debug.Assert(_items.Length < capacity); int newcapacity = _items.Length == 0 ? DefaultCapacity : 2 * _items.Length; // Allow the list to grow to maximum possible capacity (~2G elements) before encountering overflow.
// Note that this check works even when _items.Length overflowed thanks to the (uint) cast
if ((uint)newcapacity > Array.MaxLength) newcapacity = Array.MaxLength; // If the computed capacity is still less than specified, set to the original argument.
// Capacities exceeding Array.MaxLength will be surfaced as OutOfMemoryException by Array.Resize.
if (newcapacity < capacity) newcapacity = capacity; Capacity = newcapacity;
} // Gets and sets the capacity of this list. The capacity is the size of
// the internal array used to hold items. When set, the internal
// array of the list is reallocated to the given capacity.
public int Capacity
{
get => _items.Length;
set
{
if (value < _size)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.value, ExceptionResource.ArgumentOutOfRange_SmallCapacity);
} if (value != _items.Length)
{
if (value > 0)
{
T[] newItems = new T[value];
if (_size > 0)
{
Array.Copy(_items, newItems, _size);
}
_items = newItems;
}
else
{
_items = s_emptyArray;
}
}
}
}

List源码

C# 中的 数组[]、ArrayList、List的更多相关文章

  1. c#中的数组、ArrayList、List区别【转】

    首先说明C#中的Array类:Array 类是 C# 中所有数组的基类,它是在 System 命名空间中定义.Array 类提供了各种用于数组的属性和方法.关于Array类的一些属性及方法详见博文:C ...

  2. c#中的数组、ArrayList、List区别

    首先说明C#中的Array类:Array 类是 C# 中所有数组的基类,它是在 System 命名空间中定义.Array 类提供了各种用于数组的属性和方法.关于Array类的一些属性及方法详见博文:C ...

  3. java 在循环中删除数组元素

    在写代码中经常会遇到需要在数组循环中删除数组元素的情况,但删除会导致数组长度变化. package com.fortunedr.thirdReport; import java.util.ArrayL ...

  4. Java中List,ArrayList、Vector,map,HashTable,HashMap区别用法

    Java中List,ArrayList.Vector,map,HashTable,HashMap区别用法 标签: vectorhashmaplistjavaiteratorinteger ArrayL ...

  5. go语言中的数组切片:特立独行的可变数组

    go语言中的数组切片:特立独行的可变数组 初看go语言中的slice,觉得是可变数组的一种很不错的实现,直接在语言语法的层面支持,操作方面比起java中的ArrayList方便了许多.但是在使用了一段 ...

  6. 浅谈JAVA中HashMap、ArrayList、StringBuilder等的扩容机制

    JAVA中的部分需要扩容的内容总结如下:第一部分: HashMap<String, String> hmap=new HashMap<>(); HashSet<Strin ...

  7. Java中的数组与集合

    此文转载自:http://student-lp.iteye.com/blog/2082362 在java编程的过程中,我们不能确定某一类型的对象到底会需要多少,为了解决这个问题,java提供了容纳对象 ...

  8. Java 中 Vector、ArrayList、List 使用深入剖析

    线性表,链表,哈希表是常用的数据结构,在进行Java开发时,JDK已经为我们提供了一系列相应的类来实现基本的数据结构.这些类均在java.util包中.本文试图通过简单的描述,向读者阐述各个类的作用以 ...

  9. C#基础-数组-ArrayList

    数组ArrayList using System.Collections; //表示引入集合的命名空间 数组ArrayList容量本身是不固定的,根据存储的数据动态变化 // 声明一个ArrayLis ...

  10. java中一个数组不能放不同数据类型的值

    在java中,数组不能放不同数据类型的值. 方法一: 多态 定义数组类型的时候定义为父类,而存进数组为父类的子类 public class test2 { public static void mai ...

随机推荐

  1. qiankun vue子应用升级webpack5问题记录

    升级的方式是使用最新版本的 vue-cli 脚手架,重新创建一个新项目,然后复制 @vue/cli-xxx , vue 相关依赖最新版本到子应用项目 -> 核对babel, eslint相关配置 ...

  2. C# Nuget版本号排序

    Nuget包版本号和我们软件应用版本号一样,不过因为稳定性等的考虑,组件版本有更高的要求.预发布版本使用频率更高 版本号介绍,详见我朋友胡承老司机的博客:Nuget包的版本规范 (qq.com) 我这 ...

  3. 解密Prompt系列6. lora指令微调扣细节-请冷静,1个小时真不够~

    上一章介绍了如何基于APE+SELF自动化构建指令微调样本.这一章咱就把微调跑起来,主要介绍以Lora为首的低参数微调原理,环境配置,微调代码,以及大模型训练中显存和耗时优化的相关技术细节 标题这样写 ...

  4. python轻量级性能工具-Locust

    Locust基于python的协程机制,打破了线程进程的限制,可以能够在一台测试机上跑高并发 性能测试基础 1.快慢:衡量系统的处理效率:响应时间 2.多少:衡量系统的处理能力:单位时间内能处理多少个 ...

  5. 互异关系容斥&集合幂级数小记

    最近碰见了一些互异关系容斥的题目,而这类题目往往要配合集合幂级数的一些技术使用,所以简单记记. 内容很杂,行文很乱,作者水平很低,酌情观看. 互异关系容斥 思想其实很基本,应用范围其实很广. 原论文. ...

  6. ChatGPT 中文指令指南,教会你如何使用chatgpt实现中文你想要的答案

    ChatGPT 中文指令指南,教会你如何使用chatgpt实现中文你想要的答案 1.学习英语--替代词典 App 场景 例子 Prompts 解释中文英文意思,并解释单词的词根词缀.可以替代词典. 告 ...

  7. 【python】使用爬虫爬取动漫之家漫画全部更新信息

    本篇仅在于交流学习 网站名称为: https://manhua.dmzj.com/ 1.首先将相应的库导入: import requests from lxml import etree 2.确定漫画 ...

  8. selenium 执行js脚本

    使用 selenium 直接在当前页面中进行js交互 使用selenium 执行 Js 脚本 要使用 js 首先要知道 js 怎么用,现在举个简单得例子,就用12306举例子, 它的首页日期选择框是只 ...

  9. python Unitest和pytest 介绍和安装

    前言 目前有两种纯测试的测试框架,pytest和unittest,这系列文章主要介绍pytest为主 UnitTest测试框架理论 python 自带的单元测试框架,常用在单元测试 在自动化测试中提供 ...

  10. Accurate SerDes LineRate

    测试现象:(单板A板载7A series,单板B板载7K series) 1. 单板A板载2个type C接口,通过线缆自环,GTP near-end loopback, OK. 2. 2块单板A,使 ...