Jeffrey Zhao在"你的字典里有多少元素?"一文中,提到了他在面试时问过的一个问题:List<T>是怎么存放元素?不幸的是,自己也回答不出来,只知道怎么用,却不知道为啥这样用,很明显的"知其然而不知其所以然"。于是,扒了一段List<T>的一段源码来一窥究竟。

using System;
using System.Diagnostic;
using System.Collections.ObjectModel;
using System.Security.Permissions; namespace System.Collections.Generic
{
...
[Serializable()]
public class List<t> : IList<t>, System.Collections.IList
{
private const int _defaultCapacity = 4;
private T[] _items; //List<T>内部是依靠数组_items存放数据的
private int _size; //数组的长度
private int _version;
[NoSerialized]
private Object _syncRoot;
static T[] _emptyArray = new T[0]; //无参数构造函数 把_items设置成一个空的数组
public List()
{
_items = _emptyArray;
} //此构造函数 给_items数组一个初始容量
public List(int capacity)
{
...
items = new T[capaicty];
} //此构造函数 把集合类型参数拷贝给_items数组
public List(IEnumerable<t> collection)
{
...
ICollection<t> c = collection as ICollection<t>;
if(c != null)
{
int count = c.Count; //把构造函数集合类型参数的长度赋值给临时变量count
_items = new T[count]; //List<T>内部维护的_items数组的长度和构造函数集合类型参数的长度一致
c.CopyTo(_items, 0); //把构造函数集合的所有元素拷贝到_items数组中去
_size = count; //_items数组的长度就是构造函数集合类型参数的长度
}
else
{
_size = 0;
_items = new T[_defaultCapacity];
...
}
} //通过设置这个属性,改变List<t>内部维护的_items数组的长度
public int Capacity
{
get {return _items.Length; }
set {
if(value != _items.Length){ //如果当前赋值和List<t>维护的内部数组_items长度不一致
if(value < _size){
//TODO: 处理异常
}
if(value > 0){
T[] newItems = new T[value]; //创建一个临时的、新的数组,长度为新的赋值
if(_size > 0){
//把临时的、新的数组拷贝给List<t>内部维护的数组_items,注意,这时_items的长度为新的赋值
Array.Copy(_items, 0, newItems, 0, _size);
}
} else {
_items = _emptyArray;
}
}
}
} public void Add(T item)
{
if(_size == _items.Length) EnsureCapacity(_size + 1);
_items[_size++] = item;
...
} //确保List<t>内部维护的_items数组的长度至少是给定的值
//如果_items数组原先的长度比给定的值小,就让_items数组的长度设置为原先的长度的2倍
privat void EnsureCapacity(int min)
{
if(_items.Length < min){
int newCapacity = _items.Length == 0 ? _defaultCapacity : _items.Legnth * 2;
if(newCapacity < min) newCapacity = min;
Capacity = newCapacity;
}
} }
}

由此可见,向List<T>中存放元素的大致过程是这样的:

→List<T>内部维护着一个数组_items,用来存放T类型的元素。
→当有新的T类型元素存放进来,即调用Add(T item)方法。
→Add(T item)方法内部调用EnsureCapacity(int min)方法确保List<T>的Capaicty属性值至少在原先长度上加1,最多是原先长度的2倍。
→在给Capacity赋值的过程中,对_items的长度进行了扩容。
→扩容后,再把新的T类型元素存放进来。

简单地说:

当有新的元素存放到List<T>中时,List<T>先对其维护的内部数组进行扩容,然后再把新元素放进来。

C#中List<T>是怎么存放元素的的更多相关文章

  1. Leetcode(215)-数组中的第K个最大元素

    在未排序的数组中找到第 k 个最大的元素.请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素. 示例 1: 输入: [3,2,1,5,6,4] 和 k = 2 输出: 5 ...

  2. PTA 将数组中的数逆序存放

    7-1 将数组中的数逆序存放 (20 分)   本题要求编写程序,将给定的n个整数存入数组中,将数组中的这n个数逆序存放,再按顺序输出数组中的元素. 输入格式: 输入在第一行中给出一个正整数n(1). ...

  3. 在js中怎么样选择互斥的相邻元素

    在使用jquery中,我们通常会选择siblings()去选择相邻元素,使用eq()方法去匹配元素,使用index()获取对应元素的索引值,具体jquery代码如下: <style> *{ ...

  4. 寻找数组中的第K大的元素,多种解法以及分析

    遇到了一个很简单而有意思的问题,可以看出不同的算法策略对这个问题求解的优化过程.问题:寻找数组中的第K大的元素. 最简单的想法是直接进行排序,算法复杂度是O(N*logN).这么做很明显比较低效率,因 ...

  5. IT公司100题-35- 求一个矩阵中最大的二维矩阵(元素和最大)

    问题描述: 求一个矩阵中最大的二维矩阵(元素和最大).如: 1 2 3 4 5 6 7 8 9 10 1 2 3 4 5 中最大的是: 4 5 9 10   分析: 2*2子数组的最大和.遍历求和,时 ...

  6. PHP中常用的正则表达式由哪些元素构成?

    在程序开发中,我们常常要用到正则表达式,对于新手来说,很多时候知道正则表达式是怎么回事,但当真正需要使用的时候,却不知该用什么函数,具体的修饰符也比较混乱.下面小编就为大家整理了一些php正则表达式中 ...

  7. HTML 之 Web页面表单form中只有一个input的text元素,按回车默认提交

    WEB开发中,如果页面的 form 中只有一个input元素,在该input元素的输入框中按回车(注:此时并没有写对应的onkeydown等事件处理),则浏览器会默认提交表单,请看如下代码: < ...

  8. C:函数:功能:实现字符数组中所有字母的倒序存放并输出

    前两天小测碰到一道题,建立一个函数,功能:实现字符数组中所有字母的倒序存放并输出,一开始觉得简单跟数字数组差不多,运行一下发现很多格式错误,这些是不必要的错误,现在就来说下,先说一下代码思路:定义一个 ...

  9. CSS中伪类选择器及伪元素

    1.伪类选择器 在CSS中,最常用的伪类选择器是使用在a(锚)元素上的几种选择器,它们的使用方法如下: a:link{color:#FF0000;text-decoration:none} a:vis ...

随机推荐

  1. Pg168-1

    1.Pg168-1 package org.hanqi.pn0120; public class Computer { private double neicundx=10; public doubl ...

  2. Ionic实战五:ionic图表源码基于highcharts

    ionic图表demo基于Highcharts,highcharts 是一个用纯JavaScript编写的一个图表库, 能够很简单便捷的在web网站或是web应用程序添加有交互性的图表.HighCha ...

  3. thinkphp签到的实现代码

    thinkphp签到的实现代码 数据表 1 2 3 4 5 6 7 8 9 10 11 CREATE TABLE `members_sign` (   `id` int(11) unsigned NO ...

  4. CSUOJ 1726 你经历过绝望吗?两次!BFS+优先队列

    Description 4月16日,日本熊本地区强震后,受灾严重的阿苏市一养猪场倒塌,幸运的是,猪圈里很多头猪依然坚强存活.当地15名消防员耗时一天解救围困的"猪坚强".不过与在废 ...

  5. 洛谷——P2083 找人

    P2083 找人 题目背景 无 题目描述 小明要到他的同学家玩,可他只知道他住在某一单元,却不知住在哪个房间.那个单元有N层(1,2……N),每层有M(1,2……M)个房间. 小明会从第一层的某个房间 ...

  6. Linux VXLAN

    VXLAN协议 VXLAN是Virtual eXtensible Local Area Network的缩写,RFC 7348的标题“A Framework for Overlaying Virtua ...

  7. 基于Apollo实现.NET Core微服务统一配置(测试环境-单机)

    一.前言 注:此篇只是为测试环境下的快速入门.后续会给大家带来生产环境下得实战开发. 具体的大家可以去看官方推荐.非常的简单明了.以下介绍引用官方内容: Apollo(阿波罗)是携程框架部门研发的分布 ...

  8. splice() 的用法

    splice splice()方法是修改Array的“万能方法”,它可以从指定的索引开始删除若干元素,然后再从该位置添加若干元素: var arr = ['Microsoft', 'Apple', ' ...

  9. 最短网络Agri-Net

    [问题描述] 农民约翰被选为他们镇的镇长!他其中一个竞选承诺就是在镇上建立起互联网,并连接到所有的农场.当然,他需要你的帮助.约翰已经给他的农场安排了一条高速的网络线路,他想把这条线路共享给其他农场. ...

  10. JZYZOJ 2002 [cf] 石江豪pk李震 博弈论 sg函数

    http://172.20.6.3/Problem_Show.asp?id=2002 https://blog.csdn.net/qq_24451605/article/details/5015497 ...