泛型是什么
通过参数化类型来实现在同一份代码上操作多种数据类型。利用“参数化类型”将类型抽象化,从而实现灵活的复用。
泛型类
定义泛型方法就是定义一个方法,这个方法的参数的类型可以是不确定的,当调用这个方 法的时候再去确定方法的参数的类型。
情景是当需要把两个数据成员相加时候,数据成员类型固定的话,需要重复写代码,用泛型就可以根据参数的类型去判断使用什么类型
internal class Program
{
static void Main(string[] args)
{
ClassA<int> a = new ClassA<int>(1, 2);
Console.WriteLine(a.GetSum());
}
}
class ClassA<T>
{
private T a;
private T b;
public ClassA(T a, T b)
{
this.a = a;
this.b = b;
}
public T GetSum()
{
dynamic num1 = a;
dynamic num2 = b;
dynamic result = num1 + num2;
return (T)result;
}
}
直接打印对象p,等价于打印p.ToString字符串,等价于打印该对象的路径
Program p = new Program();
Console.WriteLine(p.ToString());
Console.WriteLine(p);
所以可以重写该ToString方法,让它直接打印出对象的数据成员
internal class Student
{
private int age;
private string name;
public Student(int age, string name)
{
this.age = age;
this.name = name;
}
public override string ToString()
{
string result = age + ": " + name;
return result;
}
}
static void Main(string[] args)
{
Student s = new Student(12,"小燕");
Console.WriteLine(s);
}
这样就重写的ToString方法
泛型方法
同样是为了解决代码重复性,根据参数类型选择方法T类型
同一个类中,两个静态方法,可以不同类名.方法去调用,因为同一个类只能有一个GetSum函数,但是别的类的可以有GetSum函数,要调用别的类的GetSum静态函数,就要加类名
internal class Program
{
static void Main(string[] args)
{
int result = GetSum<int>(45, 12);
Console.WriteLine(result);
}
public static T GetSum<T>(T a, T b)
{
dynamic num1 = a;
dynamic num2 = b;
return (T)(num1 + num2);
}
}
创建自己的MyList列表
引用类型的都要new,不构造不能直接调用任何成员
internal class MyList<T>
{
private T[] data = new T[0];
//所有的引用类型都要new,只声明或者赋值为null,空引用不能调用任何成员
private int count = 0; //元素个数
public int Capacity
{
get
{
return data.Length;
}
}
//Count是private的,对外界提供属性,让外界可以访问到Count值,但不能修改Count值
public int Count
{
get
{
return count;
}
}
public void Add(T item)
{
if(data.Length == 0)
{
data = new T[4];
}
//把原来数组里的值赋值到新数组中,就是扩容
if(data.Length == count)
{
T[] temp = new T[count*2];
for(int i = 0; i < data.Length; i++)
{
temp[i] = data[i];
}
data = temp;
}
data[count] = item;
count++;
}
//索引器实现
public T this[int index]
{
get
{
if(index < 0 || index > count - 1)
{
throw new System.ArgumentOutOfRangeException("索引参数超出范围了");
}
return data[index];
}
set
{
data[index] = value;
}
}
//插入实现
public void Insert(int index, T item)
{
if(index < 0 || index > count -1)
{
throw new ArgumentOutOfRangeException("索引参数超出范围了");
}
for (int i = count - 1; i > index-1; i--)
{
//count-1到index
data[i+1] = data[i];
}
data[index] = item;
count++;
}
//删除实现
public void RemoveAt(int index)
{
if(index < 0 || index > count - 1)
{
throw new ArgumentOutOfRangeException("索引参数超出范围了");
}
for(int i = index + 1; i < count; i++)
{
//从index+1到count-1
data[i-1] = data[i];
}
count--;
}
//从前遍历查找某个值的位置
public int IndexOf(T item)
{
int index = -1;
for (int i = 0; i < count; i++)
{
//如果是用==比较的话,比较的是值类型,不能比较引用类型,因为比较的是引用地址
if (item.Equals(data[i]))//使用Equals函数可以判断值类型和引用类型(只包括String等自带的),
//如果T为Student类,比较两个对象,比较的是两个引用地址,要在Student类里重写Equals方法
{
index = i; break;
}
}
return index;
}
//从后遍历查找某个值
public int LastIndexOf(T item)
{
int index = -1;
for (int i = count-1; i>=0; i--)
{
if (item.Equals(data[i]))
{
index = i; break;
}
}
return index;
}
//排序
public void Sort()
{
Array.Sort(data, 0, count);//排序数组data,从0开始,长度为count
}
}
测试
static void Main(string[] args)
{
MyList<int> list = new MyList<int>();
Console.WriteLine(list.Capacity);
list.Add(1);
list.Add(2);
list.Add(3);
list.Add(4);
list.Add(5);
list.Add(2);
list.Add(3);
Console.WriteLine(list.Count);
for(int i = 0; i < list.Count; i++)
{
Console.Write(list[i]+" ");
}
////超出范围抛出异常
//int temp1 = list[10];
//int temp2 = list[-1];
Console.WriteLine();
list.RemoveAt(3);
for(int i = 0;i < list.Count; i++)
{
Console.Write(list[i]+" ");
}
Console.WriteLine();
Console.WriteLine(list.IndexOf(2));
Console.WriteLine(list.LastIndexOf(2));
//排序
list.Sort();
for (int i = 0; i < list.Count; i++)
{
Console.Write(list[i] + " ");
}
}
Equals方法
Equals方法可以比较值类型,也可以比较一些引用类型,比如字符串,但是引用类型比较是比较地址,比如Student类,要比较两个Student类的对象,需要在Student类中,重写Equals方法,让Equals方法比较该类的数据成员,而不是引用比较
== 号比较的是值类型,比较引用类型也是比较地址,可以重载==号
Student类
internal class Student
{
public int age;
public string name;
public Student(int age, string name)
{
this.age = age;
this.name = name;
}
public override bool Equals(object obj)
{
//传入子类Student,用父类obj声明对象,类似于obj=new Student();
//再把obj对象强制转换为原来Student类,因为不能父类不能赋给子类
Student stu = (Student)obj;
if(age == stu.age && name == stu.name)
{
return true;
}
return false;
}
}
测试
static void Main(string[] args)
{
int a = 1;
int b = 1;
Console.WriteLine(a.Equals(b));//等价于a==b
String str1 = "hello";
string str2 = "hello";
Console.WriteLine(str1.Equals(str2));//内置已经重写Equals,可以实现比较字符串,但不能比较类
Student stu1 = new Student(18, "小燕");
Student stu2 = new Student(18, "小燕");
Console.WriteLine(stu1.Equals(stu2));//在Student类中,已经重写了Equals方法用于比较数据成员
Console.WriteLine(stu1 == stu2);//比较的是引用,也就是指向对象在堆的地址
}