事实上,泛型集合在处理值类型时比非泛型集合表现更优。例如 List 相比 ArrayList。
但是除了避免装箱操作以外,为什么会出现这种情况呢?一旦将值类型对象添加到集合中,它们存储在哪里?在非泛型集合中,它们会被装箱并存储在堆上,那么泛型集合有何不同之处呢?
事实上,泛型集合在处理值类型时比非泛型集合表现更优。例如 List 相比 ArrayList。
但是除了避免装箱操作以外,为什么会出现这种情况呢?一旦将值类型对象添加到集合中,它们存储在哪里?在非泛型集合中,它们会被装箱并存储在堆上,那么泛型集合有何不同之处呢?
List<T>
,它们仍然存储在堆上。区别在于,内部List<int>
会创建一个整数数组,并直接存储数字。而使用ArrayList,则会存储对装箱整数值的引用数组。List<T>
的底层存储是一个 T[] 数组。因此,对于 List<int>
来说,这些值将存储在 int[] 数组中。整数存储在从垃圾收集堆分配的连续内存块中。List<T>
实际上使用数组作为后备存储的答案(而且说得很好)。 List<T>
只是一个包装器,用于添加支持调整大小的数组,实际上几乎所有集合类型都归结为数组,除了特殊集合,如LinkedList<T>
。 - Allon GuralnekArrayList
的性能会受到双重打击。首先,您必须取消引用数组中的值以获取对象(装箱值类型),然后您必须对其进行取消装箱。 - Jim MischelArrayList
的后备存储为object[]
,那么首先您必须在数组中查找该项,这将为您提供包含int的对象的引用。您必须取消引用以获取对象,然后必须对其进行拆箱。与此相比,List
只需从int[]
后备存储中获取项目即可。 - Jim MischelArrayList是一个本地对象引用数组,存储在堆中的对象的引用。
泛型引用类型列表是一个本地对象引用数组,存储在堆中的对象的引用。
值类型的泛型列表是这些值类型的本地数组。
内存中有两个区域,大多数引用称之为“堆栈”和“堆”。使用这些术语的大多数人都不知道原因。 (“堆栈”可能是一个堆栈,但“堆”几乎肯定不是一个堆)。我更喜欢使用“这里”和“那里”的术语。当装箱时,值类型数据存储在“那边”。当存储在数组中(也许在泛型列表内部),值类型数据存储在“这里”。 “这里”更好一些。
ArrayList
和List<T>
都使用System.Array
作为内部存储,它是一个引用类型并且被存储在“那边”。 - Dirk VollmarList<T>
中,用于存储值类型的内存位于System.Array分配的内存中(即“这里”)。在ArrayList中,每个元素只是对装箱值类型的引用,因此存储每个值类型的实际内存位于“堆”上的其他位置,即“那边”。 - Dr. Wily's Apprentice泛型的性能提升通常只针对与非泛型等效物中存储的值类型相比使用泛型的值类型。
这是因为使用泛型时,值类型不需要转换为对象并存储在堆上(装箱)。实际上,它们可以保留在堆栈上,这样更具有性能优势。