版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1.1.7面向对象高级深圳市信息职业技术学院类的继承01目
录Sealed关键字02多态03抽象类和接口04异常0506命名空间和程序集知识回顾类的定义及对象构造方法this和static关键字面向对象的概念访问修饰符垃圾回收嵌套类和匿名类对象初始化器学习目标通过本节学习可以:重点学习类的继承重点学习多态重点学习抽象类和接口掌握sealed关键字掌握异常了解命名空间和程序集01类的继承类的继承继承的概念在现实生活中,继承一般指的是子女继承父辈的财产。在程序中,继承描述的是事物之间的所属关系,通过继承可以使多种事物之间形成一种关系体系。例如猫和狗都属于动物,在程序中便可认为猫和狗继承自动物,同理波斯猫和巴厘猫继承自猫,而沙皮狗和斑点狗继承自狗,这些动物之间会形成一个继承体系。具体如下图所示。类的继承继承的概念在C#中,类的继承是指在一个现有类的基础上去构建一个新的类,构建出来的新类被称作子类,现有的类被称作父类,子类会自动拥有父类所有可继承的属性和方法。例如动物和犬科的继承关系,可以用如下代码表示:classAnimal{}classDog:Animal{//Dog类继承Animal类//Dog类可以自动拥有Animal类的属性和方法}类的继承继承的概念在类的继承中,需要注意一些问题,具体如下:继承具有单一性,也就是说一个类只能有一个直接的父类,例如下面的语句是错误的。classA{}classB{}classC:A,B{}//C类不可以同时继承A类和B类classA{}classB:A{}classC:A{}//类B和类C都可以继承类A多个类可以继承同一个父类,例如下面的语句是正确的。类的继承继承的概念在C#中,多层继承是可以的,即一个类的父类可以再去继承其他类,例如C类继承自B类,B类又继承自A类,此时C类也可称作A类的子类,下面的语句是正确的。classA{}classB:A{}//B类继承自A类,B类是A类的子类classC:B{}//C类继承自B类,C类是B类的子类构造方法的执行过程构造方法的执行过程在上一章中学习了构造方法的定义以及重载,了解到构造方法可以用于初始化类的静态成员和实例成员。在继承关系中,构造方法的执行过程会变得有些不一样,下面进行具体分析。当一个类的对象被创建时,如果该类拥有父类的话,在调用自身构造方法的同时还会调用父类的构造方法,其具体执行过程如下图所示。从图中可以看出,子类在实例化对象时,首先会调用父类的构造方法,然后再调用自身的构造方法。隐藏基类方法隐藏基类方法子类在继承父类时可以对父类的成员进行扩展,如果子类中出现与父类同名的方法,那么在调用该方法时程序就不能明确该方法是属于父类还是子类,这时编译器就会提示使用new关键字隐藏基类方法。接下来通过一个案例来演示如何隐藏基类方法。隐藏基类方法隐藏基类方法程序编译出现警告,如下图所示。根据程序编译警告,将程序第9行代码添加一个new关键字,修改后的代码片段如下所示。classDog:Animal{publicnewvoidShout(){//与父类方法重名Console.WriteLine("汪汪......");}}添加new关键字隐藏基类方法隐藏基类方法运行结果,如下图所示。在示例中,Dog类继承Animal类,同时Dog类中存在与父类相同的方法Shout(),因此,使用new关键字可以明确告诉编译器执行Dog类中的Shout()方法,解决继承关系中方法同名的问题。装箱和拆箱装箱和拆箱在实际开发过程中,某些方法的参数类型为引用类型,如果调用时传入的是数值类型,此时需要进行装箱操作。同样当一个方法的返回值类型为数值类型时,实际上该方法的返回值为引用类型,此时就需要进行拆箱操作。简单来说,装箱就是将数值类型转换为引用类型,拆箱就是将引用类型转换为数值类型。接下来通过一个案例来学习装箱与拆箱操作,具体如下所示。装箱和拆箱装箱和拆箱namespaceProgram04{classProgram{staticvoidMain(string[]args){intnum=100;objectobj=num;Console.WriteLine("对象obj的值为{0}",obj);num=(int)obj;Console.WriteLine("变量num的值为{0}",num);Console.ReadKey();}}}将int类型变量num赋值给object类型的变量obj,发生装箱操作。将object类型的对象obj赋值给int类型的变量num,发生拆箱操作。装箱和拆箱装箱和拆箱运行结果,如下图所示。需要注意的是,装箱与拆箱过程本质上是数据存储在栈与堆之间的变更,如果频繁的进行装箱与拆箱操作势必会影响程序的运算效率,所以建议尽量减少相关操作。思考题简述继承的概念。如何隐藏基类的方法?02Sealed关键字sealed关键字修饰类sealed关键字修饰类在C#中,使用sealed关键字修饰的类不可以被继承,也就是不能派生子类,这样的类通常被称为密封类。接下来通过一个简单的例子来演示sealed关键字的使用。namespaceProgram05{sealedclassAnimal{publicvoidShout(){Console.WriteLine("动物叫");}}classDog:Animal{publicvoidRun(){Console.WriteLine("狗在跑");}}}sealed关键字修饰类sealed关键字修饰类程序编译报错,如下图所示。由于Animal类被sealed关键字修饰,因此当Dog类继承Animal类时,编译器中会出现“Dog”:无法从密封类型“Animal派生”的错误。由此可见,被sealed关键字修饰的类不能被其他类继承。sealed关键字修饰类sealed关键字修饰类当一个类中的方法被sealed关键字修饰后,这个类的子类将不能重写该方法。接下来通过一个案例来演示被sealed关键字修饰的方法。sealed关键字修饰类sealed关键字修饰类namespaceProgram06{......classBlackDog:Dog{publicoverridevoidShout(){Console.WriteLine("黑色狗的叫声");}}classProgram{staticvoidMain(string[]args){Dogdog=newDog();//创建Dog类对象dog.Shout();Console.ReadKey();}}}namespaceProgram06{classAnimal{publicvirtualvoidShout(){Console.WriteLine("动物的叫声");}}classDog:Animal{publicsealedoverridevoidShout(){Console.WriteLine("狗的叫声");}}......}sealed关键字修饰类sealed关键字修饰类程序编译报错,如下图所示。此时编译器已报错,报错信息为“BlackDog.Shout()”:继承成员“Dog.Shout()”是密封的,无法进行重写。说明Dog类中被sealed关键字修饰的Shout()方法不能在BlackDog类中被重写。思考题使用sealed修饰的类和方法有什么特点?03多态多态多态在设计一个方法时,通常希望该方法具备一定的通用性。例如要实现一个动物叫的方法,由于每种动物的叫声是不同的,因此可以在方法中接收一个动物类型的参数,当传入猫类对象时就发出猫类的叫声,传入犬类对象时就发出犬类的叫声。此时,可以通过多态的方式来实现这种功能。所谓多态就是当调用同一个方法时,由于传入的参数类型不同而导致执行效果各异的现象。重写父类方法重写父类方法在继承关系中,子类会自动继承父类中的方法,但有时父类的方法不能满足子类的需求,那么可以对父类的方法进行重写。当重写父类的方法时,要求子类的方法名、参数类型和参数个数必须与父类方法相同,而且父类方法必须使用virtual关键字修饰,子类方法必须使用override关键字修饰。上一节案例中,Dog类从Animal类继承了Shout()方法,该方法在被调用时会打印“动物叫”。这明显不能描述一种具体动物的叫声,Dog类对象表示犬类,发出的叫声应该是汪汪。为了解决这个问题,可以在Dog类中重写父类Animal中的Shout()方法,具体代码如下所示。重写父类方法重写父类方法namespaceProgram07{classAnimal{publicvirtualvoidShout(){Console.WriteLine("动物发出叫声");}}classDog:Animal{publicoverridevoidShout(){Console.WriteLine("汪汪......");}}......}使用virtual关键字表示可被子类重写重写父类的方法重写父类方法重写父类方法namespaceProgram07{......classProgram{staticvoidMain(string[]args){Dogdog=newDog();//创建Dog类的实例对象dog.Shout();//调用dog重写的shout()方法Console.ReadKey();}}}重写父类方法重写父类方法运行结果如下图所示。根据运行结果可知,在调用Dog类对象的Shout()方法时,程序只会调用子类重写的Shout()方法,并不会调用父类的Shout()方法。注意:子类重写父类方法时,不能使用比父类中被重写的方法更严格的访问权限,如父类方法的访问修饰符是public,子类中的方法的修饰符就不能是private。多态的实现多态的实现在C#中为了实现多态,允许使用一个父类类型的变量来引用一个子类对象,根据被引用子类对象特征的不同,得到不同的运行结果。而实现多态的方式有多种,接下来通过重写的方式来演示如何实现多态。namespaceProgram08{classAnimal{publicvirtualvoidShout(){Console.WriteLine("动物叫......");}}classCat:Animal{publicoverridevoidShout(){Console.WriteLine("喵喵......");}}......}多态的实现namespaceProgram08{......classDog:Animal{publicoverridevoidShout(){Console.WriteLine("汪汪......");}}classProgram{staticvoidMain(string[]args){Animalan1=newCat();//创建Cat对象,使用Animal类型的变量an1引用Animalan2=newDog();//创建Dog对象,使用Animal类型的变量an2引用animalShout(an1);//调用animalShout()方法,将an1作为参数传入animalShout(an2);//调用animalShout()方法,将an2作为参数传入Console.ReadKey();}publicstaticvoidanimalShout(Animalan){//接收一个Animal类型的参数an.Shout();//调用实际参数的shout()方法}}}多态的实现多态的实现多态的实现运行结果如下图所示。上述示例中实现了父类类型变量引用了不同子类的对象,调用animalShout()方法时,将父类引用的两个不同子类对象分别传入,运行结果中输出了“喵喵……”与“汪汪……”。由此可见,多态不仅解决了方法同名的问题,而且还使程序变得更加灵活,从而有效提高程序的可扩展性和可维护性。base关键字base关键字当子类重写父类的方法后,子类对象将无法直接访问父类被重写的方法。C#中提供了一个base关键字专门用于在子类中访问父类的成员,例如访问父类的字段、方法和构造方法等。接下来分两种情况来演示base关键字的具体用法。1、调用父类的字段和方法,具体语法格式如下:base.字段名base.方法名([参数1,参数2,…])为了让初学者更好的学习base关键字的使用,接下来通过一个案例来演示如何访问父类的字段和方法,具体代码如下所示。base关键字namespaceProgram09{classAnimal{publicstringname="动物类";publicvirtualvoidShout(){Console.WriteLine("动物的叫声");}}classDog:Animal{publicoverridevoidShout(){//重写父类的shout()方法base.Shout();//访问父类的成员方法}publicvoidPrintName(){//定义打印name的方法Console.WriteLine("name="+);//访问父类的成员变量}}......}base关键字Base访问父类的方法Base访问父类的字段base关键字base关键字运行结果如下图所示。由运行结果可知,子类通过base关键字可以成功访问父类中的字段和方法。base关键字base关键字2、调用父类的构造方法,具体语法格式如下:classA{//父类}classB:A{//子类publicB():base(){//使用base关键字调用父类默认构造方法}}根据前面的学习可知,继承关系中,在创建子类的对象时,父类的构造方法是默认执行的。接下来通过一个案例来演示base关键字如何访问父类的有参构造方法,具体代码如下所示。base关键字namespaceProgram10{classAnimal{publicAnimal(){Console.WriteLine("默认构造方法");}publicAnimal(stringname){//定义Animal类的有参构造方法Console.WriteLine("Animal类的有参构造方法被"+name);}}classDog:Animal{publicDog(stringname):base(name){//定义Dog类的有参构造方法Console.WriteLine("Dog类的有参构造方法被"+name);}}......}base关键字Base访问父类的有参构造方法base关键字base关键字namespaceProgram10{......classProgram{staticvoidMain(string[]args){Dogdog=newDog("执行");//实例化子类Console.ReadKey();}}}base关键字base关键字运行结果如下图所示。由运行结果可知,通过base关键字可以调用父类的构造方法。里氏转换原则里氏转换原则在现实生活中经常把某事物看作某类型,例如可以将猫和狗看作动物类型。在程序中也经常将子类对象当作父类类型来使用,这时子类与父类之间需要进行类型转换,在转换的过程中需要遵循里氏转换原则。接下来通过两种情况来说明一下里氏转换原则。1、子类对象可以直接赋值给父类变量,具体代码如下:Animalan1=newCat();//将Cat类的对象赋值给Animal类的变量Animalan2=newDog();//将Dog类的对象赋值给Animal类的变量上述示例中,Cat类与Dog类都是Animal类的子类,在实例化对象时可以将子类对象赋值给父类变量。里氏转换原则接下来通过一个具体的案例来演示这种情况,具体代码如下所示。namespaceProgram11{classAnimal{//使用virtual关键字使该方法在子类中可被重写publicvirtualvoidShout(){Console.WriteLine("Animal类中Shout()方法被执行");}}classDog:Animal{//使用override关键字重写父类Shout()方法publicoverridevoidShout(){Console.WriteLine("Dog类中的Shout()方法被执行");}}......}里氏转换原则里氏转换原则里氏转换原则namespaceProgram11{......classProgram{staticvoidMain(string[]args){Animalanimal=newDog();//子类Dog的实例直接赋值给父类型的变量animal.Shout();//调用子类Dog重写的Shout()方法animal=newCat();//子类Cat的实例直接赋值给父类型的变量animal.Shout();//调用子类Cat重写的Shout()方法Console.ReadKey();}}}做了一次里氏转换,子类Dog直接赋值给了父类,并通过父类变量调用了子类的方法做了一次里氏转换,子类Cat直接赋值给了父类,并通过父类变量调用了子类的方法里氏转换原则里氏转换原则运行结果如下图所示。由运行结果可知,子类对象可以直接赋值给父类变量,并通过父类变量可以调用子类中的方法。里氏转换原则里氏转换原则2、父类对象赋值给子类变量时需要进行强制类型转换在上一个案例的讲解中将子类对象赋值给父类变量时,直接赋值即可,但是将父类对象赋值给子类变量时需要进行强制类型转换。例如将Animal类的对象animal赋值给Dog类型变量时,需要在animal对象前面添加括号,括号中指定将父类类型转换为子类类型。接下来通过一个案例来演示将父类对象赋值给子类变量,具体代码如下所示。里氏转换原则namespaceProgram12{classAnimal{publicvoidShout(){Console.WriteLine("Animal类中Shout()方法被调用");}}classDog:Animal{publicvoidRun(){Console.WriteLine("Dog类中的Run()方法被调用");}}......}里氏转换原则里氏转换原则namespaceProgram12{......classProgram{staticvoidMain(string[]args){Animalanimal=newDog();//子类Dog指向父类Animalanimal.Shout();Dogdog=(Dog)animal;//父类对象animal强制转换为子类类型dog.Run();Console.ReadKey();}}}里氏转换原则父类对象里氏转换为子类,需要将父类对象强制转换为子类类型里氏转换原则里氏转换原则运行结果如下图所示。由运行结果可知,在继承关系中,当子类对象指向父类变量时,父类变量也可以通过强制类型转换的方式指向子类变量。Object类在C#中提供了一个Object类,它是所有类的父类,也就是每个类都直接或间接继承自该类,接下来通过一个例子来演示Object类是所有类的父类,具体代码如下所示。namespaceProgram14{classAnimal{voidShout(){//定义动物叫的方法Console.WriteLine("动物叫");}}classProgram{staticvoidMain(string[]args){Animalanimal=newAnimal();//创建Animal类的对象Console.WriteLine(animal.ToString());//调用ToString()方法并打印Console.ReadKey();}}}Object类调用了Object的ToString()方法Object类Object类运行结果如下图所示。由运行结果可知,程序成功的调用了Animal类中的ToString()方法,虽然Animal类中没有定义该方法,但是程序并没有报错。这是因为Animal类默认继承自Object类,而Object类中存在ToString()方法,在该方法中输出了对象的基本信息。Object类在实际开发中,通常希望对象的ToString()方法返回的不仅仅是基本信息,还有一些特有的信息,此时可以通过重写Object类的ToString()方法来实现。接下来通过一个案例来演示通过重写Object类的ToString()方法返回一些特有的信息,具体代码如下所示。namespaceProgram15{classAnimal{publicoverridestringToString(){//重写Object类的ToString()方法return"动物叫";}}classProgram{staticvoidMain(string[]args){Animalanimal=newAnimal();//创建Animal对象Console.WriteLine(animal.ToString());//打印animal的ToString()方法的返回值Console.ReadKey();}}}Object类重写了Object类的ToString()方法Object类Object类运行结果如下图所示。由运行结果可知,通过在Animal类中重写Object类中的ToString()方法来打印“动物叫”信息。思考题1.方法的重写需要满足什么条件?2.可以通过哪些方式实现多态?04抽象类和接口抽象类和接口抽象类和接口由abstract关键字修饰的类为抽象类,抽象类中的方法不用写方法体,抽象类中可以有抽象方法,也可以有不是抽象的方法。然而接口必须使用interface关键字来声明,接口中的方法都为抽象方法,抽象方法与接口是面向对象中必须要学习的内容。抽象类抽象类当定义一个类时,常常需要定义一些方法来描述该类的行为特征,但有时这些方法的实现方式是无法确定的。例如在前面小节中定义Animal类时,Shout()方法用于表示动物的叫声,但是针对不同的动物,叫声也是不同的,因此在Shout()方法中无法准确地描述具体是哪种动物的叫声。针对上面描述的情况,C#允许在定义方法时不写方法体,不包含方法体的方法为抽象方法,抽象方法必须使用abstract关键字来修饰,具体示例如下:abstractvoidShout();//定义抽象方法Shout()抽象类抽象类当一个类中包含了抽象方法,该类也必须使用abstract关键字来修饰,使用abstract关键字修饰的类为抽象类,具体示例如下://定义抽象类AnimalabstractclassAnimal{abstractvoidShout();//定义抽象方法Shout()}需要注意的是,包含抽象方法的类必须声明为抽象类,但是抽象类可以不包含抽象方法。另外,抽象类是不可以被实例化的,因为抽象类中有可能包含抽象方法,抽象方法是没有方法体的,不可以被调用。如果想调用抽象类中定义的方法,则需要创建一个子类,在子类中实现抽象类中的抽象方法。抽象类抽象类接下来通过一个案例来演示如何实现抽象类中的方法,具体示例如下:namespaceProgram16{abstractclassAnimal{publicabstractvoidShout();//定义抽象方法Shout()}classDog:Animal{//实现抽象方法Shout()publicoverridevoidShout(){Console.WriteLine("汪汪......");}}......}通过override实现了父类的抽象方法抽象类抽象类namespaceProgram16{......classProgram{staticvoidMain(string[]args){Dogdog=newDog();//创建Dog类的实例对象dog.Shout();Console.ReadKey();}}}抽象类抽象类运行结果如下图所示。由运行结果可知,子类Dog通过override关键字实现了父类Animal中的抽象方法后,可以进行正常的实例化,并通过实例化对象调用子类中重写的Shout()方法。接口接口如果一个抽象类中的所有方法都是抽象的,则可以将这个类用另外一种方式来定义,即接口。在定义接口时,需要使用interface关键字来声明,具体示例如下:interfaceAnimal{voidBreathe();//定义抽象方法voidRun();//定义抽象方法}由于接口中的方法都是抽象方法,因此不能通过实例化对象的方式来调用接口中的方法。此时需要定义一个类来实现接口中的所有方法。接下来通过一个案例来演示如何调用接口中的抽象方法,具体示例如下:接口接口namespaceProgram17{interfaceAnimal{voidBreathe();voidRun();}classDog:Animal{//实现Breathe()方法publicvoidBreathe(){Console.WriteLine("狗在呼吸");}//实现Run()方法publicvoidRun(){Console.WriteLine("狗在跑");}}......}接口的实现接口接口namespaceProgram17{......classProgram{staticvoidMain(string[]args){Dogdog=newDog();//创建Dog类的实例对象dog.Breathe();//调用Dog类的Breathe()方法dog.Run();//调用Dog类的Run()方法Console.ReadKey();}}}接口接口运行结果如下图所示。由运行结果可知,当调用Dog类中实现的Animal接口中的方法时,程序便会在控制台中输出“狗在呼吸”与“狗在跑”的信息。接口接口为了加深初学者对接口的认识,接下来对接口的特点进行归纳,具体如下:
1.接口中的所有方法都是抽象的,因此接口不能被实例化。
2.一个类可以实现多个接口,被实现的多个接口之间要用逗号隔开,具体示例如下:interfaceRun{程序代码......}interfaceFly{程序代码......}classBird:Run,Fly{程序代码......}接口接口
3.一个接口可以继承多个接口,接口之间用逗号隔开,具体示例如下:interfaceRunning{程序代码......}interfaceFlying{程序代码......}InterfaceEating:Running,Flying{程序代码......}思考题简述抽象类和接口的异同点。05异常什么是异常什么是异常异常是错误发生的信号,一旦程序出错就会产生一个异常,如果该异常没有被应用程序处理,那么该异常就会被抛出,程序的执行也会随之终止。为了不让程序终止,我们需要知道什么是异常、如何捕获异常、如何抛出异常等信息。尽管人人希望自己身体健康,处理的事情都能顺利进行,但在实际生活中总会遇到各种状况,比如感冒发烧,工作时电脑蓝屏、死机等等。程序运行过程中,也会发生这种非正常状况,比如程序运行时磁盘空间不足,网络连接中断,被操作的文件不存在。针对这种情况,C#程序引入了异常处理机制,通过异常处理机制对程序运行时出现的各种问题进行处理。什么是异常什么是异常接下来通过一个案例来演示什么是异常,具体示例如下:namespaceProgram19{classProgram{staticvoidMain(string[]args){intnum1=10;intnum2=0;intnum3=num1/num2;//除数为0,将抛出异常Console.WriteLine("num3="+num3);Console.ReadKey();}}}什么是异常什么是异常运行程序时,程序出现异常,具体示例如下:由上图可知,程序中出现了未处理的异常DivideByZeroException,这个异常就是由除数为0引起的。什么是异常什么是异常DivideByZeroException异常只是异常类中的一种,C#中提供了大量的异常类,这些类都继承自Exception类,接下来通过一张图来展示Exception类的继承体系,如下图所示。什么是异常什么是异常为了更好的展示异常信息,每个异常对象中都包含一些只读属性,这些属性可以描述异常的信息,通过这些属性可以更准确地找到异常出现的原因,异常对象的常用属性如下表所示。属性类型描述Messagestring此属性含有解释异常原因的消息StackTracestring此属性含有描述异常发生在位置信息InnerExceptionException如果当前异常是由另一个异常引起的,此属性包含前一个异常的引用HelpLinkstring此属性为异常原因信息提供URN或者URLSourcestring此属性含有异常起源所在的程序集的名称try…catch和finallytry…catch和finally如果程序发生了异常并立即终止,无法继续向下执行。为了解决这样的问题,C#程序中提供了一种对异常进行处理的方式——异常捕获。异常捕获通常使用try…catch语句,具体语法格式如下:try{//程序代码块}catch(ExceptionTypee){//可以是Exception类及其子类//对异常的处理}try…catch和finallytry…catch和finallyC#中的catch代码块有多种形式,不同形式的代码块用于处理不同级别的异常,具体如下:
1. 一般的catch代码块
catch后面没有任何内容,可以匹配try代码块中任意类型的异常,具体语法格式如下:catch{//对异常的处理}try…catch和finallytry…catch和finally2.特定catch代码块catch后带有异常类型,它可以匹配该类型的所有异常,具体语法格式如下:
catch(Exceptiontype){//对异常的处理}3.特定对象的catch代码块catch后不仅带有异常类型,还带有异常对象,通过异常对象可以获取异常信息,具体语法格式如下:
catch(ExceptiontypeInstID){//对异常的处理}try…catch和finallytry…catch和finally使用try...catch语句对案例中出现的异常进行捕获,具体代码如下:
namespaceProgram20{classProgram{staticvoidMain(string[]args){try{......}catch(DivideByZeroExceptione){Console.WriteLine("已处理异常信息:"+e.Message);Console.ReadKey();}catch(SystemException){Console.WriteLine("已处理系统异常");}catch{Console.WriteLine("已处理异常");}}}}try…catch和finallytry…catch和finally运行结果如下图所示。由运行结果可知,当try代码块中的代码抛出异常之后,被第一个catch代码块捕获,并执行该代码块中的代码,异常不再被抛出。在程序中,如果希望有些语句在程序无论是否发生异常都要执行,此时就可以在try…catch语句后加一个finally代码块。注意:在程序中使用异常语句时,try代码块是必须有的,而catch代码块和finally代码块必须要有一个,否则会出现编译错误。throw关键字throw关键字当程序中出现异常时,不仅可以通过try…catch代码块捕获异常,还可以使用throw关键字抛出异常对象。抛出的异常对象可以被上层的try…catch代码块捕获处理,也可以不作处理。接下来通过实例化一个异常对象来演示throw关键字的使用,具体代码如下所示。namespaceProgram22{classProgram{staticvoidMain(string[]args){//创建一个异常对象并抛出thrownewException("这是一个异常");}}}throw关键字throw关键字抛出异常如下图所示。由上图可知,程序抛出了一个未处理的异常,这是因为程序中的throw关键字不会对异常进行处理,只会抛出一个异常对象。throw关键字经常被用于将异常抛给上层代码处理,如果一直没有被处理,最后就会被操作系统捕捉到,而try…catch代码块会将程序抛出的异常直接进行处理。在实际开发中,可以将throw和try…catch配合使用。06命名空间和程序集命名空间命名空间C#中引入了命名空间的概念,可以将命名空间理解为程序定义的一个目录,使用命名空间可以有效避免类名冲突的问题,定义命名空间的示例代码。namespaceExample{ClassAnimal{voidShout(){ Console.WriteLine("动物的叫声");}}}namespace表示命名空间的关键字,Example表示命名空间的名称命名空间命名空间在实例化对象、调用方法、属性时都要使用“命名空间名.成员”的方式来引用,具体示例代码如下:staticvoidMain(string[]args){Example.Animalanimal=newExample.Animal();Console.ReadKey();}Example为命名空间名,Animal为命名空间下的成员命名空间命名空间接下来通过一段代码来使用using关键字引入Example命名空间,具体代码如下所示:usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingExample;//引用命名空间namespaceTest{classTest{staticvoidMain(string[]args){Animal=newAnimal();Console.ReadKey();}}}程序集程序集所谓的程序集就是包含一个或多个类型的定义文件和资源文件的集合,该程序集中的文件可以被其他程序使用。程序集文件可分为四个部分,分别是程序集清单、元数据、CIL、资源集,具体说明如下:程序集清单:包含描述该程序集中各元素彼此如何关联的数据集合,还包含指定该程序集的版本信息、安全标识所需的元数据、定义该程序集的范围以及解析对资源和类应用所需的元数据。元数据:提供有关程序集中定义的类型信息,包括类型的名称、基类和类型所实现的接口等。CIL:程序类型中所有的中间代码。资源集:诸如位图、指针、静态文本等。为了让初学者更好的学习如何使用程序集,接下来通过具体步骤演示程序集的生成过程以及如何引入程序集。练习✎本章练习如何使用base关键字?如何实现接口?✎预习练习非泛型集合包括哪些?泛型集合包括哪些?本章小节本章详细介绍了面向对象的高级知识,包括:详细讲解了类的继承、多态、抽象类和接口等面向对象的核心内容;介绍了sealed关键字、异常、命名空间和程序集的使用;熟练掌握本章内容,能够更快速、更高效地学习其他章节。THANKYOU深圳市信息职业技术学院——集合1.1系统技术栈介绍89非泛型集合泛型集合集合概述知识回顾类的继承多态抽象类和接口Sealed关键字异常命名空间和程序集学习目标通过本节学习可以:重点学习ArrayList集合重点学习Hashtable集合掌握List<T>泛型集合掌握Dictionary<TKey,TValue>泛型集合掌握自定义泛型了解集合概述01集合概述集合概述集合概述为了保存这些数目不确定的对象,C#中提供了一系列特殊的类,这些类可以存储任意类型的对象,并且长度可变,统称为集合。C#中集合可分为泛型集合和非泛型集合,二者均间接实现了IEnumerable接口。泛型集合位于System.Collections.Generic命名空间,它只能存储同一种类型的对象,其中最常用的是List<T>泛型集合和Dictionary<TKey,TValue>泛型集合。非泛型集合位于System.Collections命名空间,它可以存储多种类型的对象,其中最常用的是ArrayList集合和Hashtable集合。集合概述C#中提供了丰富的集合类。为了便于初学者对集合进行系统地学习,接下来通过一个图例来描述整个集合类的继承体系,如下图所示。上图中列出了程序中常用的一些集合类。其中,虚线框里填写的都是接口类型,而实线框里填写的都是具体的实现类。集合概述02非泛型集合思考题ArrayList集合常用方法包括哪些?Arraylist集合ArrayList集合就像是一个收纳盒,它可以容纳不同类型的对象。例如,可以将int、string、object等类型的对象同时加入到ArrayList集合中。ArrayList集合提供了一系列方法,接下来通过下表来列举ArrayList集合的常用方法。方法说明intAdd(objectvalue)将元素添加到ArrayList集合voidAddRange(ICollectionc)将集合或者数组添加到ArrayList集合voidClear()从ArrayList中移除所有元素boolContains(objectitem)判断某元素是否在ArrayList中intIndexOf(objectvalue)查找指定元素,并返回该元素在ArrayList中第一个匹配项的索引voidInsert(intindex,objectvalue)将元素插入ArrayList的指定索引处intLastIndexOf(objectvalue)查找指定元素,并返回该元素在ArrayList中最后一个匹配项的索引voidRemove(objectobj)从ArrayList中移除指定元素的第一个匹配项voidRemoveAt(intindex);从ArrayList中移除指定索引处的元素voidReverse()将整个ArrayList中元素的顺序反转voidSort()对整个ArrayList中的元素进行排序ArrayListArrayList集合ArrayList集合的常用方法可以对集合中的元素进行添加、删除、修改和查询等操作,具体如下:添加元素调用ArrayList对象的Add()方法、AddRange()方法、Insert()方法来添加元素,具体示例代码如下:ArrayListarr1=newArrayList();//创建ArrayList集合对象arr1//使用不同方法向集合添加多个元素
arr1.Add(134);arr1.AddRange(newArrayList(){"张三","李四"});arr1.Insert(2,'a');添加元素ArrayList集合需要注意的是,集合的长度就是元素的个数,集合的容量是随集合长度变化而变化的。如果集合的长度在1~4之间,容量的值就是4。如果集合的实际长度在5~8之间,那容量的值就变为8。以此类推,ArrayList的容量值总是以4为基本单位递增或递减。使用Insert()方法向集合中添加元素时,允许插入元素的索引值比集合的最大索引值大1,如果元素的索引值超过集合的最大索引值且范围在1以上,编译时就会报异常。添加元素ArrayList集合2.删除元素调用ArrayList的Remove()方法或RemoveAt()方法或Clear()方法删除元素,具体示例代码如下:ArrayListarr1=newArrayList();//将新建的集合对象添加到arr1集合的末尾
arr1.AddRange(newArrayList(){"张三","李四","王五"});arr1.Remove("张三");arr1.RemoveAt(0);arr1.Clear();删除元素从集合中移除指定元素的第一个匹配项从集合中移除指定索引位置的元素删除集合中所有的元素ArrayList集合3.修改元素通过集合中的索引修改ArrayList集合中的元素,具体示例代码如下:
//创建ArrayList集合对象
ArrayListarr1=newArrayList(newArrayList(){"张三","李四","王五"});Console.WriteLine("修改前集合中的元素:");ErgoArr(arr1);arr1[0]=1;arr1[1]=2;arr1[2]=3;Console.WriteLine();Console.WriteLine("修改后集合中的元素:");ErgoArr(arr1);Console.ReadKey();修改元素通过集合的索引修改arr1中的元素,由原来的“张三”、“李四”、“王五”改成了1、2、3ArrayList集合4.查询元素调用IndexOf()方法或LastIndexOf()方法查询指定元素的索引,调用Contains()方法判断集合中是否存在某个元素。具体示例代码如下:
ArrayListarr1=newArrayList(newArrayList(){1,2,3,1});ErgoArr(arr1);
intindex=arr1.IndexOf(1);Console.WriteLine("集合中第一个1的索引值为:"+index);
intlastIndex=arr1.LastIndexOf(1);Console.WriteLine("集合中最后一个1的索引值为:"+lastIndex);boolresult=arr1.Contains(2);//判断某元素是否在集合中Console.WriteLine("集合中是否包含元素2:"+result);arr1.Sort();//对集合中的元素按照默认的顺序进行排序ErgoArr(arr1);
查询元素查找指定元素,并返回该元素在集合中第一个匹配项的索引查找指定元素,并返回该元素在集合最后一个匹配项的索引ArrayList集合多学一招:通过foreach循环遍历ArrayList集合。具体语法格式如下:foreach(varitemincollection){
执行语句;}
上述语法格式中,item变量用于存储每次遍历的元素,默认情况下item为var类型,in为关键字,collection表示被遍历的集合。需要注意的是,foreach循环只能对遍历的元素进行读操作,而且只能单向遍历,也就是一个元素在整个foreach循环中只能被访问一次,因此在遍历集合中的元素时可以优先选择foreach循环,如果需要修改或多次访问集合中某个元素时,考虑使用for循环。多学一招思考题Hashtable集合常用方法包括哪些?hashtable集合C#中提供了一个Hashtable集合,该集合又被称为键值对集合,所谓键就类似于字典中的目录,值就类似于字典中的具体汉字信息,键与值是一一对应的关系,通过唯一的键能找到对应的值,因此Hashtable集合的这种特性大大提高了查询元素的效率。接下来通过一张表来列举Hashtable集合中的常用方法。方法说明voidAdd(objectkey,objectvalue)将带有指定键和值的元素添加到Hashtable集合中voidClear()从Hashtable集合中移除所有元素boolContains(objectkey)判断Hashtable集合中是否包含指定的键boolContainsValue(objectvalue)判断Hashtable集合是否包含指定的值voidRemove(objectkey)从Hashtable集合中移除带有指定键的元素Hashtable集合hashtable集合接下来通过一个案例来演示如何使用Hashtable集合中的常用方法,具体示例代码如下:Hashtableht=newHashtable();//创建Hashtable集合对象htht.Add(1,"张三");ht.Add('A',"李四");ht.Add("BB","王五");ErgoHash(ht);ht.Remove("BB");
ErgoHash(ht);ht.Clear();
Console.WriteLine("集合ht中的元素个数:"+ht.Count);Console.ReadKey();Hashtable集合调用Hashtable集合的Add()方法添加元素移除键为"BB"的元素移除Hashtable集合中所有元素hashtable集合在遍历Hashtable集合时,除了可以通过键来获取对应的值以外,还可以直接遍历集合中的值或集合中的对象。接下来通过一个例子来演示这两种遍历方式,具体示例代码如下:Hashtableht=newHashtable();//调用Hashtable的Add()方法来添加元素
ht.Add(1,"张三");ht.Add(2,"李四");ht.Add(3,"王五");//使用foreach语句来循环遍历集合中的值
foreach(objectvalueinht.Values){Console.WriteLine("当前遍历到的值为:"+value);}Console.WriteLine();Hashtable集合hashtable集合//使用foreach语句来循环遍历集合对象本身foreach(DictionaryEntrydicEninht){Console.Write(dicEn.Key+":"+dicEn.Value+"\n");}Console.ReadKey();运行结果如下图所示:Hashtable集合非泛型集合
publicclassstudent{publicintNumber{get;set;}publicstringName{get;set;}publicboolSex{get;set;}publicstudent(int_number,string_name,bool_sex){Number=_number;Name=_name;Sex=_sex;}publicoverridestringToString(){returnstring.Format("序号:{0},姓名:{1},性别:{2}",Number.ToString(),Name,Sex?"男":"女");}}
ArrayListarrayStudents=newArrayList();
privatevoidButton_Click(objectsender,RoutedEventArgse){addData0();showExemple0();}
privatevoidaddData0(){arrayStudents.Add(newstudent(1,"小颗豆一",true));arrayStudents.Add(newstudent(3,"小颗豆二",false));arrayStudents.Add(newstudent(5,"小颗豆三",true));arrayStudents.Add(newstudent(2,"小颗豆四",false));arrayStudents.Add(newstudent(4,"小颗豆五",true));arrayStudents.Add(newstudent(6,"小颗豆六",false));arrayStudents.Add("这里冒一个字符串,需要转换,如果这里是值类型还要进行装箱与拆箱,带来额外的开销!");}
privatevoidshowExemple0(){richTextBox1.AppendText("--------非泛型数组的操作(需要强制转换)--------\r\n");foreach(variteminarrayStudents){if(itemisstudent)richTextBox1.AppendText(item.ToString()+"\r\n");elserichTextBox1.AppendText((string)item+"\r\n");}}非泛型集合类在取出值时需要进行类型的转换操作,如果加入值类型会引起装箱和拆箱的操作,这会带来巨大的性能额外开销03泛型集合思考题List<T>泛型集合常用方法包括哪些?List<t>泛型集合List<student>listStudnets=newList<student>();
privatevoidButton_Click(objectsender,RoutedEventArgse){addData0();showExemple0();}
privatevoidaddData0(){listStudnets.Add(newstudent(1,"小颗豆一",true));listStudnets.Add(newstudent(3,"小颗豆二",false));listStudnets.Add(newstudent(5,"小颗豆三",true));listStudnets.Add(newstudent(2,"小颗豆四",false));listStudnets.Add(newstudent(4,"小颗豆五",true));listStudnets.Add(newstudent(6,"小颗豆六",false));}
privatevoidshowExemple0(){richTextBox1.AppendText("--------泛型数组的操作(不需要强制转换)--------\r\n");foreach(variteminlistStudnets){richTextBox1.AppendText(item.ToString()+"\r\n");}}List<t>泛型集合C#提供了一个List<T>泛型集合,该集合不仅具备ArrayList集合的功
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 二零二五版彩钢板复合板研发与销售合作协议2篇
- 2025版养老机构物业承包与运营管理合同3篇
- 二零二五版龚蝶与配偶婚姻解除及共同财产分割协议细则3篇
- 2025年度个人文化创意股权无偿转让协议4篇
- 2025版龙岗区税务局饮用水安全教育与宣传服务协议4篇
- 二零二五版股份置换与教育培训合作合同范本3篇
- 郑州体育职业学院《幼儿教师语言技能》2023-2024学年第一学期期末试卷
- 2025年度长途客运车辆挂靠管理与服务协议范本4篇
- 2025年智能出租车购置合同标准版4篇
- 基于2025年度计划的体育赛事赞助合同5篇
- 《医院财务分析报告》课件
- 2025老年公寓合同管理制度
- 2024-2025学年人教版数学六年级上册 期末综合卷(含答案)
- 2024中国汽车后市场年度发展报告
- 感染性腹泻的护理查房
- 天津市部分区2023-2024学年高二上学期期末考试 物理 含解析
- 《人工智能基础》全套英语教学课件(共7章)
- 废铁收购厂管理制度
- 物品赔偿单范本
- 《水和废水监测》课件
- 沪教版六年级数学下册课件【全册】
评论
0/150
提交评论