zoukankan      html  css  js  c++  java
  • C#中List<T>是怎么存放元素的

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

  • 相关阅读:
    gym101350 c h m
    Gym
    poj 1511 Invitation Cards(最短路中等题)
    POJ 1062 昂贵的聘礼(最短路中等题)
    POJ 1125 Stockbroker Grapevine(最短路基础题)
    【Linux】buffer cache free 理解
    python 绘图 工具
    【Linux】时间跟时区的校正
    python conda、pip区别,python 下 faiss 安装
    celery-demo
  • 原文地址:https://www.cnblogs.com/darrenji/p/3843749.html
Copyright © 2011-2022 走看看