今天上午研究了一个小知识点——泛型,想分享给大家。
总结了一下我的研究结果:泛型——集数组和集合优点于一身的好玩意儿
想这样来引出泛型:通过对数组和集合的缺点分析来唤出泛型,鉴于有些同学还不会
(或还没用过)数组和集合,我就连数组和集合也稍稍说一下下:
开始啦!!!
今天周六,下周一我要请小动物(小猫、小狗、小猪...)们吃饭,今明两天报名吃
饭“人”数,我好准备需要多少菜量
(注意以上重点:每个小动物都有‘吃’的方法(相同处),但吃的食物不一样(不同
处);去吃饭前,要先报名)
好,现在开始代码演示:
父类:动物类
//父类:动物类Animal
public class Animal
{
protected string name = "";
public Animal(string name)//构造函数
{
this.name = name;
}
public Animal()//构造函数
{
this.name = "";
}
//吃的虚方法
public virtual string Eat()
{
return "";
}
}
子类:猫类 继承动物类
//子类:猫类
class Cat : Animal //继承动物类Animal
{
//调用父类Animal的构造函数
public Cat()
: base()
{ }
public Cat(string name)
: base(name)
{ }
//重写父类函数Eat()
public override string Eat()
{
return "我是小猫,我叫" + name + "。 我吃鱼!";
}
}
子类:狗类 继承动物类
//子类:狗类
class Dog:Animal //狗类继承动物类Animal
{
//调用父类Animal的构造函数
public Dog()
: base()
{ }
public Dog(string name)
: base(name)
{ }
//Eat()函数重写
public override string Eat()
{
return "我是小狗,我叫" + name + "。 我吃骨头!";
}
}
子类:猪类 继承动物类
//子类:猪类
class Pig:Animal //猪类继承动物类Animal
{
//调用父类Animal的构造函数
public Pig()
: base()
{ }
public Pig(string name)
: base(name)
{ }
//重写父类Animal的Eat()函数
public override string Eat()
{
return "我是小猪,我叫" + name + "。 我吃馒头!";
}
}
组合实现:
客户端代码:
private Animal[] arrayAnimal;//声明一个动物数组
//点击“报名吃饭”按钮
private void btnSignUp_Click(object sender, EventArgs e)
{
arrayAnimal = new Animal[4];//实例化最多可报名4个的动物数组对象
//报名吃饭的对象:猫‘小丽’,狗‘小强’,猪‘小懒’,猫‘小红’
arrayAnimal[0] = new Cat("小丽");
arrayAnimal[1] = new Dog("小强");
arrayAnimal[2] = new Pig("小懒");
arrayAnimal[3] = new Cat("小红");
}
//点击“吃饭"按钮
private void btnEat_Click(object sender, EventArgs e)
{
foreach (Animal item in arrayAnimal)//遍历数组,让所有报名吃饭的都Eat()
{
MessageBox.Show(item.Eat()); //各自调用各自的Eat()函数,来实现吃饭
}
}
分析一下客户端代码:我们定义了一个4个长度的数组,这就限制了只能有4个动物可以
报名去吃饭,多了就不允许了,少了也不行,很不合理,不灵活。
数组优点:数组在内存中连续存储,因此可以快速容易的从头到尾遍历元素,可以
快速修改元素等等。缺点:(1)创建时必须要指定数组变量的大小;(2)在两个元
素之间添加元素很困难
鉴于数组的这两个缺点,我们用集合来实现:
客户端代码:
using System.Collections;//增加集合命名空间
IList arrayAnimal;//声明集合变量
//点击“报名吃饭”按钮
private void btnSignUp_Click(object sender, EventArgs e)
{
arrayAnimal = new ArrayList();//实例化ArrayList对象(注意:与数组不同之处是 没有指定arrayAnimal的大小)
arrayAnimal.Add(new Cat("小丽"));
arrayAnimal.Add(new Dog("小强"));
arrayAnimal.Add(new Pig("小懒"));
arrayAnimal.Add(new Cat("小红"));
}
//点击“吃饭”按钮
private void btnEat_Click(object sender, EventArgs e)
{
foreach (Animal item in arrayAnimal)//遍历ArrayList集合
{
MessageBox.Show(item.Eat());//各自实现各自的Eat()函数,来实现吃饭
}
}
再分析客户端代码:与数组相比,
集合优点: (1)不用事先设置大小,它可以根据使用大小按需增加,也就是说如果
明天 “狗小胖”和“猫小兰”也要报名去吃饭,那么可以直接增加arrayAnimal.Add
(new Dog("小胖"));arrayAnimal.Add(new Cat("小兰"));
(2)可以随意地添加、插入或移除元素,比数组方便灵活
比如:猫小丽下周一要去相亲,去不了啦。arrayAnimal.RemoveAt(0);
虽说集合的确有着数组没有的方便和灵活,但是,问题又来了——我邀请的是动物去吃
饭,如果在报名期间有其他种类(比方说“人”)也报名去吃饭:arrayAnimal.Add
(new Person("张三")); 不想接受他,他也来了,怎么办?
(注意:Person类不继承Animal类,它是一个单独的类,这里没有写出来)
集合ArrayList的不足:ArrayList不管什么对象都是接受的,因为在它眼里所有
元素都欧式Object,这就使得如果你‘arrayAnimal.Add(new Person("张三"));’或者
‘arrayAnimal.Add(123);’‘arrayAnimal.Add("Good Morning");’在编译时都是没有问题
的,但在执行时,‘foreach(Animal item in arrayAnimal)’需要明确集中的元素的类型不
匹配错误,换句话说,ArrayList不是类型安全的。还有就是ArrayList对于存放值类型的
数据,比如int、string(string是一种拥有值类型特点的特殊引用类型)或者结构struct
的数据,用ArrayList就意味着都需要将值类型装箱为Object对象,使用集合元素时,还
需要执行拆箱操作,这就带来了很大的性能损耗。
(关于数据类型哪些属于值类型,哪些属于引用类型,大家自己查资料学习!)
装箱:把值类型打包到Object引用类型的一个实例中。比如整型变量i被“装箱”并赋值
给对象obj:
int i=123;
Object obj=(object) i; //装箱
拆箱:从对象中提取值类型。上例中对象obj拆箱并将其赋值给整型变量i:
Obj=123;
i=(int)obj; //拆箱
相对简单的赋值而言,装箱和拆箱过程需要进行大量的计算。对值类型进行装箱时,必
须分配并构造一个全新的对象。其次,拆箱所需的强制转换也需要进行大量的计算。总
之,装箱拆箱是耗费资源和时间的。而ArrayList集合在使用值类型数据时,其实就是不
断地做装箱和拆箱的工作,这显然很糟糕、很影响性能。
哎呀,数组收事先设置大小的控制,又不可随意添加、移除;集合吧又什么类型都接
受,并且不断装拆箱影响性能。该怎么办呢??哈哈泛型来喽。。。
泛型(概念):具有有占位符(类型参数)的类、结构、接口和方法,这些占位符是
类、结构、接口和方法所存储或使用的一个或多个类型的占位符,泛型集合类可以将类
型参数用作它所存储的对象的类型的占位符;类型参数作为其字段的类型和器方法的参
数类型出现。
概念很抽象。
其实关键就是:给集合加上类型,让该集合只能接受某一类型的对象
关键就是:在IList和List后面加‘<T>’,这个‘T’及时需要指定的集合的数据或对象类型
泛型实现:
客户端代码:
using System.Collections.Generic;//增加泛型集合命名空间
//声明一个泛型集合变量,用接口IList,注意:IList<Animal>表示此集合变量只能接受Animal类型,其他不可以。比较与声明集合变量IList arrayAnimal;的不同——是不是多了一个<Animal>,这个Animal就是这个集合能接受的对象类型
IList<Animal> arrayAnimal;
//点击“报名吃饭”按钮
private void btnSignUp_Click(object sender, EventArgs e)
{
arrayAnimal = new List<Animal>();//实例化List对象,此时也要指定List<T>的‘T’是Animal
arrayAnimal.Add(new Cat("小丽"));
arrayAnimal.Add(new Dog("小强"));
arrayAnimal.Add(new Pig("小懒"));
arrayAnimal.Add(new Cat("小红"));
}
//点击“吃饭”按钮
private void btnEat_Click(object sender, EventArgs e)
{
foreach (Animal item in arrayAnimal)//遍历泛型集合
{
MessageBox.Show(item.Eat());//各自实现各自的Eat()函数,来实现吃饭
}
}
如果现在‘张三’再想报名arrayList.Add(new Person("张三"));会有什么后果?嘿嘿,
报错呗,因为泛型集合arrayAnimal不接受出Animal类型(或Animal子类型)以外的类型
对象。
泛型的优点:其实List和ArrayList在功能上是一样的,不同之处:泛型在声明和实
例化时都需要指定内部项的数据或对象类型,这就避免了集合的类型不安全问题和拆装
箱的性能问题了。