Java程序设计系列讲座.ppt_第1页
Java程序设计系列讲座.ppt_第2页
Java程序设计系列讲座.ppt_第3页
Java程序设计系列讲座.ppt_第4页
Java程序设计系列讲座.ppt_第5页
已阅读5页,还剩81页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

Java程序设计系列讲座2OOP之封装性,黄绍辉厦门大学计算机科学系E-mail:hsh,面向对象程序设计基本思想,对象的基本概念对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。对象是问题域或实现域中某些事物的一个抽象,它反映该事物在系统中需要保存的信息和发挥的作用;它是一组属性和有权对这些属性进行操作的一组服务的封装体。客观世界是由对象和对象之间的联系组成。,类的基本概念,类是具有相同属性和服务的一组对象的集合。分类的原则是抽象。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性说明和服务说明两个主要部分。类与对象的关系就如模具和铸件的关系,类的实例化结果就是对象,而对一类对象的抽象就是类。,关于OOPObjectOrientedProgramming,对象是基本编程单位。与此对应,Java使用类(class)表示对象,一个class就是一个类;对象由一组属性和一组服务两部分组成(两部分不必都存在)。与此对应,Java使用一组成员变量(membervariable)表示属性,一组成员函数(membermethod)表示服务。,OOP的例子,例如我们要表示一个遥控器对象,它起码有两个属性:外壳,按钮。它起码有两个功能:换台,调音量。使用Java来设计这个对象,它看起来就是这个样子:class遥控器外壳成员按钮成员换台函数()调音量函数(),OOP的基本特征,封装性把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节。继承性从一个已有的类来构造新类,除了保留原有的类的特性,还增加了一些新特性。已有的类称为父类superclass,新类称为子类subclass。多态性在父类中定义的属性或服务被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。,OOP-PartI封装性,从C语言开始出发,任务:在程序中实现对时间的一些操作思路:时间是一个整体,包括时/分/秒,为了在程序中表示一个具体的时间,这三个部份缺一不可。最自然的,可以采用三个整型变量来存储这三个部份,例如:inthour;intminute;intsecond;,C程序示例,voidmain()inthour,minute,second;hour=12;minute=12;second=12;printf(“Timeis%d:%d:%d”,hour,minute,second);,如果有很多个时间,voidmain()inthour1,minute1,second1;inthour2,minute2,second2;inthour3,minute3,second3;printf(“Time1is%d:%d:%d”,hour1,minute1,second1);printf(“Time2is%d:%d:%d”,hour2,minute2,second2);printf(“Time3is%d:%d:%d”,hour3,minute3,second3);,如果用数组,voidmain()inthour100,minute100,second100;for(inti=0;ihour+;,使用示例:structMyTimet;t=AddOneHour(t);,使用示例:structMyTimet;AddOneHour(,关于上面两个函数的探讨,前面说过,structMyTime已经可以看成是对象了,从上面的两个函数可以看出,为了修改对象的属性,比较好的作法,是(通过指针)直接修改对象本身的属性,代码简单,效率也高。但是C毕竟是面向过程的语言,实现“对象的加工”或者叫“对象的服务”,需要借助structMyTime之外的函数AddOneHour完成。OOP语言的第一个方便之处,就是把属性和服务整合到同一个对象中,这给编程带来了极大的方便,例如:,Java版本的AddOneHour,classMyTimeinthour;intminute;intsecond;voidAddOneHour()hour+;,使用示例:MyTimet=newMyTime();t.AddOneHour();,把属性和服务整合到同一个对象内部的最大好处,是你不再需要将一个结构作为一个参数传入到外部的处理函数,也不需要考虑将处理后的结果从函数传出,甚至贴代码的时候,都不用担心会少贴一个函数,看出封装的好处了吗?,C的结构可以存储数据,但是不能包含函数,因此必须在其它的地方定义函数。这个做法可能导致以下后果:调用不方便,参数要传入传出毕竟是比较麻烦的可能和别人写的函数产生冲突(例如重名)代码的重用和修改不方便Java可以将数据和处理函数一起封装,因此数据以及对数据的加工都可以在同一个对象当中完成。,总结一下封装性,OOP中,对象就是对一组变量和相关方法的封装,其中变量表明了对象的状态,方法表明了对象具有的行为。简单一点说,封装性指的是:属性和函数都放在同一个对象的内部。对Java而言就是:一个class可以内部可以有多个成员变量和多个成员函数;成员函数可以直接访问成员变量,并对其进行修改。通过对象的封装,实现了模块化和信息隐藏。,跑步进入OOP有个例子,从简单对象入手,对象不是很深奥的东西,一个对象在Java里面就是一个class而已。例如随便写一个对象:classPoint/首字母大写是Java建议的对象命名规则intx,y;这个Point对象可以用来表示平面上的一个点。注意Java并不要求对象一定要有成员函数,所以这个对象已经很完整,只是还不够好用而已,接下来我们会逐步完善它。,对象的用法,要使用一个已有的对象不是太难,但是你要做足以下的两件事情:使用对象的名字声明一个变量创建对象的一个实例用上面的Point做例子,就是这样:使用对象的名字声明一个变量Pointp;创建对象的一个实例p=newPoint();接下来这个p就拥有了Point的全部资源,例如它有两个成员变量,叫x,y,而且还是整型的。,对象的用法,对象的声明和创建可以合成一步:Pointp=newPoint();当然也可以隔了很多步:Pointp;/*中间有很多很多很多行,但是和p无关*/p=newPoint();只有一个准则:对象在创建之前是不能使用的,所以new很重要。,对象与实例,前面说到,对象必须创建才能使用,所以你必须这样创建p:Pointp=newPoint();这里引入几个术语:Point是类名,也是对象名,或者干脆叫对象p是对象的实例,也就是Point的实例你可以理解对象是一个图章,它每盖章一次(new一次)生成一个p,p就是一个实例。,一个完整例子:Test.java,classPointintx,y;publicclassTestpublicstaticvoidmain(Stringargs)Pointp=newPoint();System.out.println(“p.x=”+p.x+“p.y=”+p.y);p.x=1;p.y=2;System.out.println(“p.x=”+p.x+“p.y=”+p.y);,插播一下:数组,使用对象,我们刚刚学会两招:招式一:对象可以同时拥有属性和函数;招式二:对象要new以后才能使用下面我们来用这两招对付Java的一个常用对象:数组。和C语言不同,Java把数组设计成了对象,所以根据我们的招式二,Java的数组必须先new才能使用。如果你能够意识到这一点,那么恭喜你,OOP入门成功,数组入门1,1声明一个数组dataTypearrayRefVar;或dataTypearrayRefVar;例如:doublemyList;2创建一个数组arrayRefVar=newdataTypearraySize;如:myList=newdouble10;,数组入门2,声明并创建一个数组dataTypearrayRefVar=newdataTypearraySize;或dataTypearrayRefVar=newdataTypearraySize;例如:doublemyList=newdouble10;,数组入门3,数组在创建之后,Java会为这个数组自动分配空间。(注意声明数组的时候并没有分配数组元素空间,因为那时候不知道数组多大),数组入门4,任何一个数组,都可以通过属性length得到数组的长度。如:myList.length数组创建的时候会自动赋零值,对于数值型的,就是0或者0.0或者0,对于布尔型的,就是false任何一个数组,其元素的最小下标是0,最大下标是length-1数组下标越界会引发异常,数组入门5,数组元素的引用使用,以下两个方法可以打印出数组myList的每一个元素值:for(inti=0;imyList.length;i+)System.out.print(+myListi);或者(JDK1.5以上版本才支持的)for(intval:myList)System.out.print(+val);,数组入门6,数组在创建的时候可以顺便初始化,如:doublemyList=1.9,2.9,3.4,3.5;它相当于:doublemyList=newdouble4;myList0=1.9;myList1=2.9;myList2=3.4;myList3=3.5;,数组例程1/3,用100以内随机数初始化数组for(inti=0;imyList.length;i+)myListi=Math.random()*100;,数组例程2/3,数组求和doubletotal=0;for(inti=0;imyList.length;i+)total+=myListi;,数组例程3/3,求数组中的最大值doublemax=myList0;for(inti=1;imax)max=myListi;,数组作为函数参数1,数组作为参数,Java采用的是引用传递方式,基本数据类型(int,char等)作为参数,采用值传递方式。简单一点说,引用传递方式,实际参数和形式参数,操作的其实是同一个对象;值传递方式,实际参数和形式参数,操作的是不同对象,仅仅是这两个对象的值相等而已。,数组作为函数参数2,publicclassTestpublicstaticvoidmain(Stringargs)intx=1;/xrepresentsanintvalueinty=newint10;/yrepresentsanarrayofintvaluesm(x,y);/InvokemwithargumentsxandySystem.out.println(xis+x);/x值不变,还是1System.out.println(y0is+y0);/y0值已改变,本来是0的publicstaticvoidm(intnumber,intnumbers)number=1001;/Assignanewvaluetonumbernumbers0=5555;/Assignanewvaluetonumbers0,数组作为函数参数3,1publicclassTestPassArray2/*Mainmethod*/3publicstaticvoidmain(Stringargs)4inta=1,2;56/Swapelementsusingtheswapmethod7System.out.println(Beforeinvokingswap);8System.out.println(arrayis+a0+,+a1+);9swap(a0,a1);/值传递,返回后不改变原值10System.out.println(Afterinvokingswap);11System.out.println(arrayis+a0+,+a1+);1213/SwapelementsusingtheswapFirstTwoInArraymethod14System.out.println(BeforeinvokingswapFirstTwoInArray);15System.out.println(arrayis+a0+,+a1+);16swapFirstTwoInArray(a);/引用传递,返回后原值可能改变17System.out.println(AfterinvokingswapFirstTwoInArray);18System.out.println(arrayis+a0+,+a1+);19,数组作为函数参数4,20/值传递,返回后不改变原值21/*Swaptwovariables*/22publicstaticvoidswap(intn1,intn2)23inttemp=n1;24n1=n2;25n2=temp;2627/引用传递,返回后原值可能改变28/*Swapthefirsttwoelementsinthearray*/29publicstaticvoidswapFirstTwoInArray(intarray)30inttemp=array0;31array0=array1;32array1=temp;3334,多维数组1,二维数组的定义dataTypearrayRefVar;或dataTypearrayRefVar;例如:intmatrix;或intmatrix;注意,这里仅仅说明matrix是一个二维数组,但是这个数组的大小还未知,所以还不能存储元素。,多维数组2,二维数组有行和列的概念,如:,多维数组3,二维数组可以在声明的时候赋初值,也可以在new之后再一个一个慢慢赋值。其实二维数组行和行之间是相互独立的,每一行都相当于一个一维数组。,由于二维数组的每一行是一个一维数组,所以这些一维数组的大小不必相等,如:此时:triangleArray.length=5,/因为数组有5行triangleArray0.length=5,triangleArray1.length=4,triangleArray2.length=3,triangleArray3.length=2,triangleArray4.length=1.,多维数组4,二维数组例程1,随机数填充for(introw=0;rowmatrix.length;row+)for(intcolumn=0;columnmatrixrow.length;column+)matrixrowcolumn=(int)(Math.random()*100);这里matrix是二维数组。过一遍二维数组必须用两层的循环,一般用i循环行,j循环列;如果英文好一点,可以用row循环行,column或者col循环列。,二维数组例程2,打印数组元素for(introw=0;rowmatrix.length;row+)for(intcolumn=0;columnmatrixrow.length;column+)System.out.print(matrixrowcolumn+);System.out.println();,二维数组例程3,数组求和inttotal=0;for(introw=0;rowmatrix.length;row+)for(intcolumn=0;columnmatrixrow.length;column+)total+=matrixrowcolumn;,杨辉三角的例子,publicclassYanghuipublicstaticvoidmain(Stringargs)inta=newint1010;for(inti=0;i10;i+)for(intj=0;j=i;j+)if(j=0|i=j)aij=1;if(i9)ai+1j+1=aij+aij+1;System.out.print(aij+);System.out.println();,研究一下构造函数,创建对象,前面说到,对象必须创建才能使用,那么创建对象Point是不是只有一种方法呢?默认的显然是只有一种,所以你只能这样创建p:Pointp1=newPoint();但是实际生活里,我们必须有多种途径来创建对象,这样用起来才方便。例如你可能希望这样创建:Pointp2=newPoint(1,2);然后期待着p2的x和y成员分别是1和2,如何做到这一点呢?,什么是构造函数,可不可以换一种方式创建Point?当然可以,不过你要自己加构造函数,例如:classPointintx,y;Point(intxx,intyy)x=xx;y=yy;注意上面那个函数,它有两大神奇之处:没有定义返回值,连void都没有名字和类的名字完全一样这种写法奇怪的函数就是传说中的:构造函数,默认构造函数,现在你终于可以这样创建一个p了:Pointp=newPoint(1,2);不过你现在反而不能这样创建一个p了:Pointp=newPoint();why?,关于构造函数I,构造函数和类的名字完全一样,并且没有返回值,它的作用是提供类的创建方式,所以,根据类必须先创建再使用的原则,构造函数是每一个类一定要具备的东西。或许你注意到第一个版本的Point没有构造函数,是的,不过Java是这样聪明的一个语言,所以它会帮你补充一个不带参数,没有函数体的构造函数,例如Point类,它偷偷加的代码是:classPointintx,y;Point()/这一行尽管你没看见,但是它确实存在,关于构造函数II,Java自动提供构造函数仅仅当你自己没有提供构造函数的时候才这么干,如果你提供了哪怕只有一个的构造函数,它决不自作多情帮你加一个。所以第二个版本的Point最好改成下面:classPointintx,y;Point()/由于Java罢工,这个函数只好自己加Point(intxx,intyy)x=xx;y=yy;,关于成员变量对内篇,每一个类都可以有自己的成员变量,例如Point类的x和y;对于Point类的内部而言,x,y相当于全局变量;如果脱开Point类,那么就要看x,y是怎么声明的了。classPointPoint()x=10;y=10;Point(intxx,intyy)x=xx;y=yy;intx,y;,x,y的作用范围从这里开始,x,y的作用范围到这里结束,关于成员变量对外篇,成员变量有四种修饰,它们决定了外部访问成员变量的权限:private,default,protected、public对于private,实际上是不允许外部访问的,所以如果你的Point这样定义:classPointprivateintx,y;然后有Pointp=newPoint();那么这两个语句是错的:p.x=10;p.y=10;,关于成员变量对外篇,如果这个时候你想从外面修改x,y的值怎么办?答案是:没法改!除非Point类另外提供函数给你用,例如:classPointprivateintx,y;publicintgetX()returnx;/这就是传说中的getterpublicvoidsetX(intxx)x=xx;/传说中的setter上帝保佑,现在你终于可以从外面改x的值了:Pointp=newPoint();p.setX(100);System.out.print(p.getX();,关于成员函数I,成员函数的访问权限和成员变量完全一样,所以这里不重复了。成员函数的调用,也要通过对象的实例才能够调用(当然静态函数除外,后面再讲),不会忘记什么叫对象的实例了吧?Oh,myGod!还是加一个函数试试,例如我们给Point加一个成员函数:publicdoubletest(doubles)returnx*y*s;,关于成员函数II,现在我们来调这个函数(这里是在外部调,如果在类的内部调,那就直接调用就好了)Pointp=newPoint(3,4);System.out.print(p.test(5.0);/通过p调用test函数还是不太放心,演示一下对象内部怎么调test:classPointprivateintx,y;publicdoublef()returntest(5.0);publicdoubletest(doubles)returnx*y*s;,关于成员函数III,总结一下,一个类的成员函数:对于类的内部而言,是直接抓过来随便爱怎么调用都行(多大公无私啊),不需要借助任何东西;对于类的外部而言,如果是private的成员函数,那显然是不能用的;如果遇到public的,那运气还不错,可以通过创建一个类的实例(也就是new一下),来间接调用这个成员函数。成员变量的结论与此类似。顺便说一下,在一个类的外部,每次new一个实例的时候,相当于调用一次构造函数;至于调用的是哪一个构造函数,那要看你给的参数了。,关于静态方法和静态成员I,如果一个class有一个static的成员,那使用的时候要小心一点。给一个例子:classApublicintx;publicstaticinty;publicstaticvoidf()System.out.print(x+y);还记得怎么调用f,怎么使用x,y么?很简单:Aa=newA();/看到这句不要晕掉,好多a.a.x=10;a.y=10;a.f();/调用函数f,不要参数,关于静态方法和静态成员II,下面来一段复杂的测试代码,测试A这个类:classTestpublicstaticvoidmain(Stringargs)Aa=newA();a.x=10;a.y=10;Ab=newA();b.x=100;b.y=100;System.out.print(a.x=+a.x+a.y=+a.y+b.x=+b.x+b.y=+b.y);运行上面程序,你会发现一个奇怪的现象:a.x不等于b.x,可是a.y居然等于b.y前一半比较好理解,因为a和b本来就是不同的实例,虽然它们是一个模子造出来的;可是,那y怎么回事?,关于静态方法和静态成员III,其实,静态成员是如此特殊的一个东西,因为它是所有实例共享的!也就是无论你new多少个实例出来,静态成员自始至终就是一个而已。而且,就算是你没有new过实例,它就已经存在了,神奇吧?所以,java鼓励你这样直接使用静态成员:A.y=100;A.f();/注意这里没有实例噢,A亲自上阵了所以,静态成员变量在java里一般被用作共享的常数,例如Math.PI,所以你可以常常看到final和static一起混的情形;静态成员函数一般被用作全局函数,供任意类调用,例如Math.sin(),再次啰唆一下类成员的访问控制,类成员总共有四种访问模式:private,protected,public以及default,它们的访问控制如下:确定访问控制权限的原则基于安全性的考虑,在能满足设计要求的前提下,访问权限越严格越好,一个例子,classRootprivateinta;protectedfloatb;publicdoublec;chard;voidfun()a+;b+;c+;d+;/类的内部,成员变量相当于全局/变量,在任何函数中均可直接用假设有一个类的实例Rootr=newRoot();那么r.a+就是错误的,因为这相当于在类的外部使用变量;但是r.c+是正确的,因为c是public,支持外部访问。,关于封装的进一步探讨,Java的封装属性有四个(按开放程度排序):private,default,protected以及public。一般来说,封装越严格越好,因此尽量不要将成员变量设置为public。当把成员变量设置为private时,为了能够提供外部类对这些成员变量的存取,一般要设置一堆的public的get方法和set方法。例如对hour成员:publicintgetHour()returnhour;publicvoidsetHour(inth)hour=h;,方法重载,方法重载是指多个方法享有相同的名字,但是这些方法的参数必须不同,或者是参数的个数不同,或者是参数类型不同。返回类型不能用来区分重载的方法。,再次啰唆一下构造方法,构造方法是一个特殊的方法。Java中的每个类都有构造方法,用来初始化该类的一个对象。构造方法具有和类名相同的名称,而且不返回任何数据类型。重载经常用于构造方法。构造方法只能由new运算符调用。,关于构造方法以及new,要生成一个对象的实例,必须使用new运算符。每次new的时候,对象的构造方法会被自动调用。构造的方法可能有很多个,new的时候调用哪一个取决于new的时候带的参数。例如:MyTimet1=newMyTime();/调用无参数的构造方法MyTimet2=newMyTime(hour,second,minute);/调用使用三个参数的构造方法,注意三个参数的类型/要和构造方法声明的参数类型保持一致,一个练习,写一个类Person表示一个人,用name和age表示其姓名和年龄,并提供以下三个构造函数:Person();/默认名字为noname,年龄为0Person(Stringname);/年龄默认为0Person(Stringname,intage);在main函数中使用以上三种构造方式创建3个Person对象,然后输出。,异常,异常和异常类型,异常是程序运行时发生的错误。当异常发生时,常常导致程序崩溃,从而丢失尚未保存的数据。用户输入非法是异常的主要来源,例如:,异常是可以捕捉的,Java允许你自己去捕捉异常,从而避免程序崩溃。例如上例可以修改为:,异常处理(I),异常分类:受检异常(编程时一定要检测的异常)非受检异常异常的层次:,异常处理(II),异常产生:运行时(被动)产生主动抛出throw异常处理捕获try.catch(ExceptionName1e).catch(ExceptionName2e).finally.,异常处理(III),try捕获例外的第一步是用try选定捕获例外的范围,由try所限定的代码块中的语句在执行过程中可能会生成例外对象并抛弃。catch每个try代码块可以伴随一个或多个catch语句,用于处理try代码块中所生成的例外事件。ca

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论