求知若饥,虚心若愚
如果没有泛型
- 使用通用算法时要经常装箱拆箱(除非显式为特定类型实现)
- 可空值类型的实现依赖Object或者显式为特定类型实现
- 装箱拆箱导致的类型不安全
泛型概述
优点
- 泛型促进了类型安全
- 编译时的类型检查减少了运行时发生InvalidCastException异常的概率
- 值类型避免装箱拆箱
- 缓解了代码膨胀
- 性能得以提高,不用装箱拆箱,和类型转换相关的类型检查
- 内存消耗减少,同样由于不用装箱
- 代码可读性更好
指定默认值
使用default来对不确定类型的值取默认值
约束
- 使用接口类型约束,避免了非要转型才能调用一个显式的接口成员实现
- 类类型约束必须第一个出现,不允许多个类类型约束
- struct/class约束,值类型或引用类型约束
- 构造函数约束,new(),要求类型实参必须有默认构造函数
- 类约束不会继承,但子类必须用相同或更强的约束,不然无法继承
- 虚函数的约束会被继承,还能增加额外的约束(不建议,会破坏多态性)
- 由于构造约束只能约束默认构造,并不能约束有参,所以需要通过提供工厂接口来包含对该类型实例化的方法
协变性和逆变性
- 协变:假定两个类型x和y具有特殊关系,即每个x类型的值都能转换成y类型。如I
和I 也总是具有相同的特殊关系,那么"I 对T协变",该转换称为协变转换。 - 逆变:假定两个类型x和y具有特殊关系,即每个x类型的值都能转换成y类型。如I
和I 也总是具有相反的特殊关系,也就是说每个I 类型的值都能转换成I 类型,那么"I 对T逆变"。 - out类型参数修饰符允许协变性,编译器验证只用作"输出",而不用于形参或属性的赋值
- in类型参数修饰符允许逆变性,编译器验证只作为"输入",即不能用于getter或者方法返回值
- 使用out,in限制:只有泛型接口和泛型委托才可以,参与变化的必须是引用类型,接口或委托必须声明协变或逆变(编译器必须验证)
这里补充我的理解:先说结论,out和in其实就是一种高级约束,避免你类型不安全的操作。首先是协变,一个苹果是水果,一袋苹果是不是一袋水果呢,这里要从引用的角度出发,一袋苹果只能新增苹果,而一袋水果不止能新增苹果,如果一袋水果能引用一袋苹果,那可以通过一袋水果来新增一个香蕉,从而影响原有的一袋苹果(由于是引用,会影响原有内存),那此时这袋苹果就不对了,如果通过一袋苹果这个原有对象去逐个读取的时候就会运行时错误了。所以如果禁止一袋水果的新增功能,那么一袋水果就可以引用一袋苹果,这点是安全的,也就是协变的。逆变其实是相反的操作,应该用于子类和父类都有共同的操作,比如比较函数,所以直接用父类的应用于子类,就不用重复代码?当创建可由大量类使用的更加通用的委托方法时,使用逆变就更为简单了。适合任何对象的行动必定适合任何他的子类,所以逆变委托/接口才能生效。