前言:
很少有代码能做到不使用集合,如List<T>或Dictionary<K,V>。大型应用可能会同时使用成千上万个集合。对大多数应用来说,根据需要选择或自己编写适当的集合类型,能够带来极大的性能提升。阅读本文你将知道:
1.为什么要有泛型
2.为什么说Java是假泛型
3.CLR泛型的实现
4.泛型约束
5.有哪些集合
6.线程安全集合
7.集合的内存布局方式对性能的影响
为什么要有泛型
我们常常需要创建能用于任何数据类型的类或方法,多态和继承并不总能"药到病除"。在.Net2.0之前,如果方法需要适配任意类型,就只能使用System.Object。这会带来两个问题。
1.类型安全
2.装箱
PS:装箱等基础知识,需自行百度
为什么说Java是假泛型
Java编译泛型代码的方式是:移除任何与泛型类型参数有关的信息,取而代之的是Java.lang.Object,这一过程称为类型擦除。
因为使用Object,编译器可以保持统一,解决了类型安全的问题。但是却解决不了拆装箱。
CLR泛型的实现
CLR泛型实现:泛型类型(即便是List<>这样的开放类型)是运行的重中之重。每个泛型类型都有一个方法表和EEClass,同时也能生成System.Type实例。当CLR创建封闭类型(List<int>)实例的时候,会根据其开放类型创建方法表和EEClass。
如果检查实际的方法体,就会发现引用类型的代码不依赖实际类型,只是围绕着引用做文章。而值类型的代码则依赖实际类型,毕竟复制一个整数和一个浮点数是不同的。
泛型约束
泛型约束告诉编译器,在使用某个泛型时,只有某些类型能够作为泛型实参。
public T Create<T>(T element) where T : EntityBase
{
}
public T Create<T>(T element) where T : EntityBase
{
}
public T Create<T>(T element) where T : IFormattable
{
}
public T Create<T>(T element) where T : new()
{
}
public T Create<T>(T element) where T : class
{
}
public T Create<T>(T element) where T : struct
{
}
有哪些集合
List<t>
LinkedList<T>
Dictionary<K,V>
HashSet<T>
Queue<T>
Stack<T>
SortedDictionary<K,V>
SortedList<K,V>
SortedSet<T>
线程安全集合
ConcurrentStack<T>
ConcurrentQueue<T>
ConcurrentBag<T>
ConcurrentDictionary<K,V>
集合的内存布局方式对性能的影响
选择正确的集合所要考虑的不仅仅是性能。对CPU密集型应用来说,数据在内存的布局方式远比其他条件重要,而集合会显著地影响内存布局。
因内存布局会影响到使用CPU缓存。
例如:遍历LinkedList<int>和int[],遍历int数组的性能要快上几倍
在访问数组的元素是,在缓存行开始会有一次缓存未命中,就是会将一个缓存行的数据放入缓存(一个缓存行是64字节)。即16个整数,缓存命中率1:16。但是链表会有前后指针,一个指针4字节,引用类型还有对象头和方法表指针(32位对齐4,64位对齐8),可见缓存命中率该有多低。
总结:
请选择合理的集合甚至自定义集合来提升性能吧!
网友评论