C#中List<T>存放元素的工作机制

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>先对其维护的内部数组进行扩容,然后再把新元素放进来。

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,谢谢大家对我们的支持。如果你想了解更多相关内容请查看下面相关链接

(0)

相关推荐

  • C# List<T>的用法小结

    所属命名空间:System.Collections.Generic     public class List<T> : IList<T>, ICollection<T>, IEnumerable<T>, IList, ICollection, IEnumerable List<T>类是 ArrayList 类的泛型等效类.该类使用大小可按需动态增加的数组实现 IList<T> 泛型接口. 泛型的好处: 它为使用c#语言编写面向对象程

  • C# 如何实现一个带通知的List<T>

    背景 在很多场景下面我们需要在集合发生变化的时候能够通过一个事件对外进行通知,默认的List<T>并没有此类功能,所以对于这一类需求的业务场景下我们需要自己进行相关的扩展,这样才能够符合我们这一需求,这里我来列举一个在项目中经常用到的一个扩展类,在后面我们会对这个进行具体的分析和使用到的C#知识点进行关注. 实现 这里贴出具体的代码实现 using System; using System.Collections.Generic; using System.Linq; namespace XX

  • 关于C#泛型列表List<T>的基本用法总结

    示例代码如下:namespace SampleListT{  class Program  {      static void Main(string[] args)      {//using System.Collections.Generic; 命名空间中的List<T>//using System.Collections; 命名空间中的ArrayList  //都实现了列表集合,一个是泛形集合,一个是非泛型的//下面我们将Person对象加到集合中 Person p1 = new P

  • C# 泛型集合类List<T>使用总结

    目录 为什么选择使用List,而不是使用Array,或者ArryList 去重.交集.并集.差集操作 重写Equals() 和 GetHashCode() 简单使用 C#中List可谓是使用最广泛的一种数据类型了,使用他来规范数据时,往往会涉及到对数据的处理操作,相关处理数据方法也非常丰富,本文将简单介绍为何使用它,以及部分处理方法的灵活使用. 为什么选择使用List,而不是使用Array,或者ArryList 首先要说下数组的局限性 (1) 数组中元素是固定的:类型和数量都必须确定!一旦定义,

  • 浅谈C#中List<T>对象的深度拷贝问题

    一.List<T>对象中的T是值类型的情况(int 类型等) 对于值类型的List直接用以下方法就可以复制: List<T> oldList = new List<T>(); oldList.Add(..); List<T> newList = new List<T>(oldList); 二.List<T>对象中的T是引用类型的情况(例如自定义的实体类) 1.对于引用类型的List无法用以上方法进行复制,只会复制List中对象的引用,

  • C#中List<T>存放元素的工作机制

    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> : ILi

  • Javascript从数组中随机取出不同元素的两种方法

    一.常规算法 第一种方法较常规,经测试有bug,数据量大以后随机几次返回的对象直接是function而不是object. 当然简单数据类型应该没有这个问题. 示例代码 /** 从数组中随机抽取数据 2016-09-09 **/ function getArrItem(arr, num) { var temp_array = new Array(); for (var index in arr) { temp_array.push(arr[index]); } var return_array =

  • Java中ArrayList去除重复元素(包括字符串和自定义对象)

    1.去除重复字符串 package com.online.msym; import java.util.ArrayList; import java.util.Iterator; @SuppressWarnings({ "rawtypes", "unchecked" }) public class Demo1_ArrayList { public static void main(String[] args) { ArrayList list = new Array

  • 如何在sae中设置django,让sae的工作环境跟本地python环境一致

    sae中安装有python环境,想让sae导入自己下载的django或者其他模块,可以在svn中新建一个文件目录,比如site-packages,跟python安装目录一样,这个目录存放所有的python模块(包括django),将安装目录下的以及用pip install安装的各种模块copy入这个目录,然后增加python搜索路径,让sae可以从这个目录引入各种模块,保证程序正常运行.具体设置如下: 第一步:修改wsgi.py文件,该文件在django生成的项目目录后,比如../mysite/

  • 浅谈Python中的可迭代对象、迭代器、For循环工作机制、生成器

    1.iterable iterator区别 要了解两者区别,先要了解一下迭代器协议: 迭代器协议是指:对象需要提供__next__()方法,它返回迭代中的元素,在没有更多元素后,抛出StopIteration异常,终止迭代. 可迭代对象就是:实现了迭代器协议的对象. 协议是一种约定,可迭代对象实现迭代器协议,Python的内置工具(如for循环,sum,min,max函数等)通过迭代器协议访问对象,因此,for循环并不需要知道对象具体是什么,只需要知道对象能够实现迭代器协议即可. 迭代器(ite

  • 使用Iterator删除List中的多个元素操作

    今天在写代码时要删除List中的多个元素时犯了一个很搞笑的错误,等效的就是以下代码 public static void main(String[] args) { List<String> a = new ArrayList<String>(); a.add("1"); a.add("2"); a.add("3"); a.add("4"); a.add("5"); Iterator

  • 面试题:java中为什么foreach中不允许对元素进行add和remove

    目录 1.foreach遍历ArrayList过程中使用 add 和 remove 2.追根溯源 2.1.modCount是什么? 2.2.expectedModCount 是什么? 2.3.熟悉的checkForComodification方法 2.4.流程回顾 3.避免fail-fast 机制 3.1.使用listIterator或iterator 3.2.使用CopyOnWriteArrayList 3.2.1.CopyOnWriteArrayList的add方法 3.2.2.CopyOn

  • 详解如何在Angular中快速定位DOM元素

    在使用Angular2+中,经常会想快速的去选择DOM上的某个元素,如果是刚上手Angular,有可能直接就使用原生DOM操作或者导入jQuery再进行DOM操作,既然都使用了Angular了,有没有更好的方法呢?答案是肯定的. 通过ElementRef 先上代码: import {Component, ElementRef, OnInit} from '@angular/core'; @Component({ selector: 'app-root', templateUrl: './app.

  • tomcat中Servlet的工作机制详细介绍

    tomcat中Servlet的工作机制 在研究Servlet在tomcat中的工作机制前必须先看看Servlet规范的一些重要的相关规定,规范提供了一个Servlet接口,接口中包含的重要方法是init.service.destroy等方法,Servlet在初始化时要调用init方法,在销毁时要调用destroy方法,而对客户端请求处理时则调用service方法.对于这些机制的支持都必须由Tomcat内部去支持,具体则是由Wrapper容器提供支持. 在tomcat中消息流的流转机制是通过四个不

  • java删除数组中的某一个元素的方法

    实例如下: package org.company.project.test; import java.util.Arrays; import java.util.Scanner; public class ArraysDelete { public static void main(String[] args) { //删除数组中的某一个元素的方法: //把最后一个元素替代指定的元素,然后数组缩容 Scanner sc =new Scanner(System.in); int[] arr =

随机推荐