CS4L5——泛型

泛型

泛型实现了类型参数化,达到代码重用目的,通过类型参数化来实现同一份代码上多种操作类型
泛型相当于类型占位符,定义类或方法时使用替代符代表变量类型,当真正使用类或者方法时在再具体指定类型

申明泛型时,它只是一个类型的占位符,泛型真正起作用的时候是在使用它的时候
泛型占位字符可以有 n 个,用逗号隔开,泛型占位字母一般是大写字母
不确定泛型类型时 获取默认值 可以用 default(占位字符)​,看到 <>​ 包裹的字母 那肯定是泛型

关键字:<>

泛型分类

  • 泛型类和泛型接口

    基本语法:

    • class 类名<泛型占位字母>
    • interface 接口名<泛型占位字母>
  • 泛型函数
    基本语法:函数名<泛型占位字母>(参数列表)

注意:泛型占位字母可以有多个,用逗号分开,常用泛型占位字母是 T

泛型类和泛型接口

泛型类在声明时,泛型参数可以替代成员的类型,实例化时,需要传入具体的类型,泛型就会替换为传入的类型

泛型接口是同理的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class TestClass<T>
{
//实例化时,T填入什么,里面的T代表的变量类型就是什么
public T Value;
}

internal class Program
{
static void Main(string[] args)
{
//可以使用所有的变量类型,填入什么类型,泛型占位字母就代表是什么类型
TestClass<int> t = new TestClass<int>();
t.Value = 10; //t的Value类型就是int
Console.WriteLine(t.Value);

TestClass<string> t2 = new TestClass<string>();
t2.Value = "hello"; //t的Value类型就是string
Console.WriteLine(t2.Value);
}
}

输出:

1
2
10
hello

泛型可以有多个,使用不同的占位符即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
class TestClass2<T1, T2, K, M, L, Key, Value>
{
public T1 value1;
public T2 value2;
public K key;
public M map;
public L l;
public L l2;
public Value value7;
}

internal class Program
{
static void Main(string[] args)
{
//有多少个泛型就填入几个类型
TestClass2<int, string, float, double, TestClass<int>, uint, ushort> t3
= new TestClass2<int, string, float, double, TestClass<int>, uint, ushort>();
}
}

泛型接口的声明和使用是同理的,继承有泛型的接口,接口的泛型必须要指定类型(可以是自己的泛型)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface ITestInterface<T>
{
T Value { get; set; }
}

class Test : ITestInterface<int> //继承有泛型的接口,接口的泛型必须要指定类型
{
int ITestInterface<int>.Value { get; set; }
}

class TestT<T> : ITestInterface<T> //继承有泛型的接口,接口的泛型必须要指定类型
{
int ITestInterface<T>.Value { get; set; }
}

泛型方法

普通类的泛型方法,使用 default​ 可以得到传入的类型的默认值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Test2
{
//泛型可以为参数, 实例化后使用该方法时要指定类型
public void TestFun<T>(T value)
{
Console.WriteLine(value);
}

//泛型可以既不作为返回值也不作为参数
public void TestFun<T>()
{
//无参方法也可以为泛型方法,用泛型类型在里面做一些逻辑类型
//不能对泛型变量直接赋一些指定类型的值,可以赋值默认值
T t = default(T);
}

//泛型可以作为返回值
public T TestFun<T>(string V)
{
return default(T);
}

//也可以使用多个泛型字母
public void TestFun<T, K, M>(T value, K key, M map) { }
}

internal class Program
{
static void Main(string[] args)
{
Test2 tt = new Test2();
tt.TestFun(123);
}
}

输出:

1
123

泛型类的泛型方法,泛型类和普通类可以共用一个类名,因为并不是一个类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Test2<T>
{
public T value;

//这种不是泛型方法,因为T在泛型类申明的时候就指定了 在使用这个函数的时候不能再去动态的变化了
public void TestFun(T t) { }

//只有带尖括号的方法才是泛型方法,注意泛型类里的泛型方法所用的泛型占位字符不能和类所用的泛型占位字符相同!
public void TestFun<K>(K k)
{
Console.WriteLine(k);
}
}


internal class Program
{
static void Main(string[] args)
{
Test2<int> tt2 = new Test2<int>();
tt2.TestFun(10);
tt2.TestFun("hello"); //泛型有时可以省略指明,因为参数里写的内容已经指明了泛型是什么类型
tt2.TestFun(1.2f);
tt2.TestFun<int>(20);
}
}

输出:

1
2
3
4
123
hello
1.2
20

泛型的作用

不同类型的对象的相同逻辑就可以选择泛型,使用泛型可以一定程度的避免装箱拆箱

举例:优化 ArrayList

1
2
3
4
5
6
class ArrayList<T>
{
private T[] array;
public void Add(T value) { }
public void Remove(T value) { }
}