一、概念
泛型是2.0推出来的新语法,它不是语法糖 而是由框架升级提供的功能。
主要知识点
- 引入泛型:延迟声明
- 如何声明和使用泛型
- 泛型的好处和原理
- 泛型类、泛型接口、泛型方法、泛型委托
- 泛型约束
- 协变、逆变
- 泛型缓存
泛型应用场景:它是用来解决用一个方法,满足不同参数类型,做相同的事的。
泛型声明:
(没有写死参数类型,调用的时候才给指定类型 延迟思想)
public static void Show<T>(T tParameter){
代码内容·····
}
object类型
public static void ShowObject(Object tParameter){
代码内容·····
}
区别:object类型是一切类型的父类,通过继承,子类可以拥有父类的一切属性和行为;任何父类出现的地方 ,都可以用子类来代替
object类型是一个引用类型,假设传入的值是int类型的话,就有一个装箱操作,方法调用的时候也会有个拆箱操作,会影响性能。
泛型为啥能做到声明的时候不指定参数类型,而调用的时候指定类型的呢?
需要编译器支持+JIT支持,依赖于编译器的升级。
编译器编译的时候会生成一个占位符~1,然后JIT再次编译的时候会将占位符替换成真正的类型。
泛型类:
//声明
public class GenericClass<T>
{
public T _t;
}
参数可多个
public class GenericClass<T,S,X>
{
public T _t;
public S _s;
public X _x;
}
//使用
GenericClass<int,string,char> t = new GenericClass<int,string,char>()
{
_t = 123,
_s = "123",
_x = 'a'
};
//普通类继承泛型类
public class CommonClass
:GenericClass<int,string,char>//必须指定
或者
public class GenericClassChild<Eleven>:GenericClass<Eleven>
也可以public class GenericClassChild<Eleven>:GenericClass<int> 这里的GenericClass<int>相当于一个普通类型,可以被继承
泛型接口
public interface IGenericInterface<T>
{
T getT(T t);//泛型类型的返回值
}
继承:
public class CommonClass
:IGenericInterface<int>//必须指定
{
public int getT(int t)
{
.........
}
}
泛型委托
public delegate void SayHi<T>(T t);//泛型委托
泛型约束
//类型结构如下
public interface ISports
{
void PingPang();
}
public interface Work
{
void Work();
}
public class people
{
public int Id{get;set;}
public string Name{get;set;}
public void Hi()
{
console.WriteLine("你好!");
}
}
public class Chinese:people,ISports,IWork
{
public void Tradition()
{
console.WriteLine("中国传统文化博大精深");
}
public void SayHi()
{
console.WriteLine("你好,吃饭了吗?");
}
public void PingPang()
{
console.WriteLine("打乒乓球。。。。");
}
public void Work()
{
console.WriteLine("工作。。。。");
}
}
public class Hubei:Chinese
{
public string Changjiang{get;set;}
public void Majiang()
{
console.WriteLine("打麻将啦。。。。");
}
}
public class Japanese:ISports
{
public int Id{get;set;}
public int Name{get;set;}
public void PingPang()
{
console.WriteLine("打乒乓球。。。。");
}
public void Hi()
{
console.WriteLine("你好!");
}
}
//使用
People people = new People()
{
Id = 123;
Name= "人类"
};
Chinese people = new Chinese()
{
Id = 234;
Name= "中国人"
};
Hubei people = new Hubei()
{
Id = 345;
Name= "湖北人"
};
Japanese people = new Japanese()
{
Id = 456;
Name= "日本人"
};
//使用
public class Constraint
{
//基类约束(不能约束Int32),必须是非密封的
//1:可以使用基类的一切属性、方法
//2:强制保证T一定是People或者People的子类
public static void Show<T>(T tParameter)
where T :People//约束
{
console.WriteLine($"{tParameter.Id}_{tParameter.Name}"); //添加约束之后可以对People类进行访问
tParameter.Hi();
}
//为啥不用这个基类方法呢? 当上面那个方法
//public static void Show<T>(T tParameter)
// where T :People,ISports,Iwork 约束可以叠加,基类不能叠加所有用约束更灵活。
public static void ShowBase(People tParameter)
{
console.WriteLine($"{tParameter.Id}_{tParameter.Name}"); //添加约束之后可以对People类进行访问
tParameter.Hi();
}
}
Constraint.Show<People>(people);
Constraint.Show<Chinese>(Chinese);
Constraint.Show<Hubei>(Hubei);
Constraint.Show<Japanese>(Japanese);//这句话会报错,因为Japanese没有继承people
//接口约束
public static T Get<T>(T t)
where T:ISports //只有实现了ISport接口的才可以传进来
{
t.PingPang();
return t;
}
//引用类型约束
public static T Get<T>(T t)
where T:class //T必须是引用类型才能传进来
{
T tNew = null;
return t;
}
//值类型约束
public static T Get<T>(T t)
where T:struct //T必须是值类型才能传进来
{
T tNew = default(T);//会根据T的不同赋予默认值,如果是引用类型就是null,如果是int是0等等
return t;
}
//无参数构造函数约束
public static T Get<T>(T t)
where T:new() //无参数构造函数
{
T tNew = new T();
return t;
}
协变、逆变