资源描述
,目录,本章小结,第三章 面向对象(上),面向对象的概念,构造方法,this,和,static,类与对象,内部类,思考:可以定义什么?,3.1,面向对象的概念,3.2,类与对象,3.3,构造方法,3.4,this,关键字,3.5,垃圾回收,3.6,static,关键字,3.7,内部类,3.8,Java,的帮助文档,3.1,面向对象的概念,面向对象是一种符合人类思维习惯的编程思想。现实生活中存在各种形态不同的事物,这些事物之间存在着各种各样的联系。在程序中使用对象来映射现实中的事物,使用对象的关系来描述事物之间的联系,这种思想就是面向对象。,面向过程就是分析解决问题所需要的步骤,面向对象则是把解决的问题按照一定规则划分为多个独立的对象,然后通过调用对象的方法来解决问题。,面向对象的特点主要可以概括为封装性、继承性和多态性,。,3.2,类与对象,面向对象的编程思想力图在程序中对事物的描述与该事物在现实中的形态保持一致。为了做到这一点,面向对象的思想中提出两个概念,即类和对象。,类是对某一类事物的抽象描述,而对象用于表示现实中该类事物的个体。,类和对象的关系如同玩具和玩具模型的关系。,可以将玩具模型看作是一个类,将一个个玩具看作对象,从玩具模型和玩具之间的关系便可以看出类与对象之间的关系。类用于描述多个对象的共同特征,它是对象的模板。对象用于描述现实中的个体,它是类的实例,并且一个类可以对应多个对象,3.2,类与对象,3.2.1,类的定义,在,面向对象的思想中最核心就是对象,为了在程序中创建对象,首先需要定义一个类。类是对象的抽象,它用于描述一组对象的共同特征和,行为,类中可以定义成员变量和成员方法,其中成员变量用于描述对象的特征,也被称作属性,成员方法用于描述对象的行为,可简称为方法,3.2,类与对象,3.2.1,类的定义,定义一个,Person,类,Person,是类名,,age,是成员变量,,speak(),是成员方法。在成员方法,speak(),中可以直接访问成员变量,age,。,3.2.2,对象的创建与使用,应用程序想要完成具体的功能,仅有类是远远不够的,还需要根据类创建实例对象。,在,Java,程序中可以使用,new,关键字来创建对象,具体格式如下:,例如,创建一个,Person,对象,具体示例如下:,3.2,类与对象,3.2,类与对象,3.2.2,对象的创建与使用,“,new Person(),”用于创建,Person,类的一个实例对象,“,Person p,”则是声明了一个,Person,类型的变量,p,。中间的等号用于将,Person,对象在内存中的地址赋值给变量,p,,这样变量,p,便持有了对象的引用,,变量,p,和对象之间的引用关系如下图所示。,3.2,类与对象,3.2.2,对象的创建与使用,在创建,Person,对象后,可以通过对象的引用来访问对象所有的成员,具体格式如下:,看一个例子,具体如下:,3.2,类与对象,3.2.2,对象的创建与使用,在例程,3-2,中,通过“,p1.age=18,”将,p1,对象的,age,属性赋值为,18,,没有对,p2,对象的,age,属性进行赋值,,但,p2,对象的,age,属性也是有值的,其值为,0,。这是因为在针对不同类型的成员变量,,Java,虚拟机会赋予不同的初始值,3.2,类与对象,3.2.2,对象的创建与使用,当对象被实例化后,在程序中可以通过对象的引用变量来访问该对象的成员,。,当没有任何变量引用这个对象时,它将成为垃圾对象,不能再被使用。,情况,1,:变量超出作用域变为垃圾对象,3.2,类与对象,3.2.2,对象的创建与使用,情况,2,:变量的值变为,null,运行结果,在例程3-3中,创建了一个Person类的实例对象,并两次调用了该对象的say()方法。第一次调用say()方法时可以正常打印,但在第10行代码中将变量p2的值置为null,当再次调用say()方法时抛出了空指针异常。在Java中,null是一种特殊的常量,当一个变量的值为null时,则表示该变量不指向任何一个对象。在例程中,当把变量p2置为null时,被p2所引用的Person对象就会失去引用,成为垃圾对象,3.2,类与对象,3.2.3,类的设计,假设要在程序中描述一个学校所有学生的信息,可以先设计一个学生类(,Student,),在这个类中定义两个属性,name,、,age,分别表示学生的姓名和年龄,定义一个方法,introduce(),表示学生做自我介绍。根据上面的描述设计出来的,Student,类如例程,3-4,所示,3.2,类与对象,3.2.4,类的封装,先来看一个例子,具体如下:,运行结果,在例程,3-5,的第,5,行代码中,将年龄赋值为一个负数,-30,,这在程序中不会有任何问题,但在现实生活中明显是不合理的。为了解决年龄不能为负数的问题,在设计一个类时,应该对成员变量的访问作出一些限定,不允许外界随意访问。这就需要实现类的封装。,3.2,类与对象,3.2.4,类的封装,所谓类的封装是指在定义一个类时,将类中的属性私有化,即使用,private,关键字来修饰,私有属性只能在它所在类中被访问,为了能让外界访问私有属性,需要提供一些使用,public,修饰的公有方法,其中包括用于获取属性值的,getXxx,方法和设置属性值的,setXxx,方法,3.2,类与对象,3.2.4,类的封装,使用,private,关键字将属性,name,和,age,声明为私有,getName(),方法用于获取,name,属性的值,,setName(),方法用于设置,name,属性的值,getAge(),和,setAge(),方法用于获取和设置,age,属性的值。在,setAge(),方法中对参数,stuAge,的值进行检查,,3.3,构造方法,3.3.1,构造方法的定义,在一个类中定义的方法如果同时满足以下三个条件,该方法称为构造方法,具体如下:,方法名和类名相同,方法名的前面没有返回值类型的,声明,方法中不能使用,return,语句返回一个值,3.3,构造方法,3.3.1,构造方法的定义,在例程,3-7,的,Person,类中定义了一个无参的构造方法,Person(),。从运行结果可以看出,,Person,类中无参的构造方法被调用了。这是因为第,9,行代码在实例化,Person,对象时会自动调用类的构造方法,“,new Person(),”语句的作用除了会实例化,Person,对象,还会调用构造方法,Person(),3.3,构造方法,3.3.1,构造方法的定义,在一个类中除了定义无参的构造方法,还可以定义有参的构造方法,通过有参的构造方法就可以实现对属性的赋值,例程,3-8,的,Person,类中定义了有参的构造方法,Person(int a),。第,13,行代码中的“,new Person(20),”会在实例化对象的同时调用有参的构造方法,并传入了参数,20,。在构造方法,Person(int a),中将,20,赋值给对象的,age,属性。通过运行结果可以看出,,Person,对象在调用,speak(),方法时,其,age,属性已经被赋值为,20,。,3.3,构造方法,3.3.2,构造方法的重载,与普通方法一样,构造方法也可以重载,在一个类中可以定义多个构造方法,只要每个构造方法的参数类型或参数个数不同即可,例程,3-9,的,Person,类中定义了两个构造方法,它们构成了重载。在创建,p1,对象和,p2,对象时,根据传入参数的不同,分别调用不同的构造方法。从程序的运行结果可以看出,两个构造方法对属性赋值的情况是不一样的,其中一个参数的构造方法只针对,name,属性进行赋值,这时,age,属性的值为默认值,0,。,脚下留心,在,Java,中的每个类都至少有一个构造方法,如果在一个类中没有定义构造方法,系统会自动为这个类创建一个默认的构造方法,这个默认的构造方法没有参数,在其方法体中没有任何代码,即什么也不做。,下面程序中,Person,类的两种写法效果是完全一样的。,脚下留心,如果,为该类定义了构造方法,系统就不再提供默认的构造方法了,运行结果,从图,3-12,可以看出程序在编译时报错,其原因是调用,new Person(),创建,Person,类的实例对象时,需要调用无参的构造方法,而我们并没有定义无参的构造方法,只是定义了一个有参的构造方法,系统将不再自动生成无参的构造方法,3.4 this,关键字,1,、,通过,this,关键字可以明确地去访问一个类的成员变量,解决与局部变量名称冲突问题,,具体示例如下:,在上面的代码中,构造方法的参数被定义为,age,,它是一个局部变量,在类中还定义了一个成员变量,名称也是,age,。在构造方法中如果使用“,age,”,则是访问局部变量,但如果使用“,this.age,”则是访问成员变量。,3.4 this,关键字,2,、,通过,this,关键字调用成员方法,具体示例代码如下:,在上面的,speak(),方法中,使用,this,关键字调用,openMouth(),方法。注意,此处的,this,关键字可以省略不写,也就是说上面的第,6,行代码写成“,this.openMouth(),”和“,openMouth(),”,效果是完全一样的,3.4 this,关键字,3,、,构造方法是在实例化对象时被,Java,虚拟机自动调用的,在程序中不能像调用其它方法一样去调用构造方法,但可以在一个构造方法中使用“,this(,参数,1,参数,2),”的形式来调用其它的构造方法通过,this,关键字调用成员方法,3.4 this,关键字,注意:,1,、只能在构造方法中使用,this,调用其它的构造,方法,2,、在构造方法中,使用,this,调用构造方法的语句必须位于第一行,且只能出现一,次,,,下面的写法是非法,的,。,3,、不能在一个类的两个构造方法中使用,this,互相,调用,3.5,垃圾回收,当,一个对象成为垃圾后仍会占用内存空间,时间一长,就会导致内存空间的不足。针对这种情况,,Java,中引入了垃圾回收,机制,Java,虚拟机就会启动垃圾回收器将这些垃圾对象从内存中释放,从而使程序获得更多可用的内存,空间,除了等待,Java,虚拟机进行自动垃圾回收,也可以通过调用,System.gc(),方法来通知,Java,虚拟机立即进行垃圾回收。当一个对象在内存中被释放时,它的,finalize(),方法会被自动调用,3.5,垃圾回收,在例程,3-13,的,Person,类中定义了一个,finalize(),方法,该方法的返回值必须为,void,,并且要使用,public,来修饰。在,main(),方法中创建了两个对象,p1,和,p2,,然后将两个变量置为,null,,这意味着新创建的两个对象成为垃圾了,紧接着通过“,System.gc(),”语句通知虚拟机进行垃圾回收。从运行结果可以看出,虚拟机针对两个垃圾对象进行了回收,并在回收之前分别调用两个对象的,finalize(),方法。,3.6 static,关键字,3.6.1,静态变量,在一个,Java,类中,可以使用,static,关键字来修饰成员变量,该变量被称作静态,变量,静态变量被所有实例共享,可以使用“类名,.,变量名”的形式来,访问,static,关键字只能用于修饰成员变量,不能用于修饰局部变量,否则编译会报错,下面的代码是非法的。,3.6 static,关键字,3.6.1,静态变量,例程,3-14,的,Student,类中定义了一个静态变量,schoolName,,用于表示学生所在的学校,它被所有的实例所共享。由于,schoolName,是静态变量,因此可以直接使用,Student.schoolName,的方式进行调用,也可以通过,Student,的实例对象进行调用,如,stu2.schoolName,。在第,8,行代码将变量,schoolName,赋值为“,黄淮学院,”,通过运行结果可以看出学生对象,stu1,和,stu2,的,schoolName,属性均为“,黄淮学院,”。,“,黄淮学院,”;,3.6 static,关键字,3.6.2,静态方法,被,static,关键字修饰的方法称为静态方法,同静态变量一样,静态方法可以使用“类名,.,方法名”的方式来访问,也可以通过类的实例对象来访问,。,在一个静态方法中只能访问用,static,修饰的成员,原因在于没有被,static,修饰的成员需要先创建对象才能访问,而静态方法在被调用时可以不创建任何对象。,3.6 static,关键字,3.6.2,静态方法,例程,3-15,的,Person,类中定义了静态方法,sayHello(),,在第,8,行代码处通过“,Person.sayHello(),”的形式调用了静态方法,由此可见静态方法不需要创建对象就可以调用。,3.6 static,关键字,3.6.3,静态代码块,在,Java,类中,使用一对大括号包围起来的若干行代码被称为一个代码块,用,static,关键字修饰的代码块称为静态代码,块,当类被加载时,静态代码块会执行,由于类只加载一次,因此静态代码块只执行一,次,在程序中,,通常使用,静态代码块来对类的成员变量进行初始化,3.6 static,关键字,3.6.3,静态代码块,从图,3-19,所示的运行结果可以看出,程序中的两段静态代码块都执行了。在命令行窗口输入“,java Example14,”后,虚拟机首先会加载类,Example14,,在加载类的同时就会执行该类的静态代码块,紧接着会调用,main(),方法。在该方法中创建了两个,Person,对象,但在两次实例化对象的过程中,静态代码块只执行一次,这就说明类在第一次使用时才会被加载,并且只会加载一次,3.6 static,关键字,3.6.4,单例模式,设计模式就是针对这些问题和需求,在大量的实践中总结和理论化之后优选的代码结构、编程风格、以及解决问题的思考方式,单例模式是,Java,中的一种设计模式,它是指在设计一个类时,需要保证在整个程序运行期间针对该类只存在一个实例,对象,看一个实现了单例模式的类,3.6 static,关键字,3.6.4,单例模式,类,的,构造方法使用,private,修饰,声明为私有,这样就不能在类的外部使用,new,关键字来创建实例对象了,。,在类,的,内部创建一个该类的实例对象,并使用静态变量,INSTANCE,引用该对象,由于变量应该禁止外界直接访问,因此使用,private,修饰,声明为私有,成员,为了,让,类的外部能够获得类的实例对象,需要定义一个静态方法,getInstance(),,用于返回该类实例,INSTANCE,。由于方法是静态的,外界可以通过“类名,.,方法名”的方式来访问,3.7,内部类,3.7.1,成员内部类,在一个类中除了可以定义成员变量、成员方法,还可以定义类,这样的类被称作成员内部类,。,在,成员内部类中可以访问外部类的所有,成员,例程,3-20,中,,Outer,类是一个外部类,在该类中定义了一个内部类,Inner,和一个,test(),方法,其中,,Inner,类有一个,show(),方法,在,show(),方法中访问外部类的成员变量,num,,,test(),方法中创建了内部类,Inner,的实例对象,并通过该对象调用,show(),方法,将,num,值进行打印。从运行结果可以看出,内部类可以在外部类中被使用,并能访问外部类的成员,3.7,内部类,3.7.1,成员内部类,如果,想通过外部类去访问内部类,则需要通过外部类对象去创建内部类对象,创建内部类对象的具体语法格式如下,:,针对例程,3-20,中定义的,Outer,类写一个测试,程序,运行结果同例程,3-20,一样,如图,3-21,所示,。,3.7,内部类,3.7.2,静态内部类,可以使用,static,关键字来修饰一个成员内部类,该内部类被称作静态内,部类,,,它可以在不创建外部类对象的情况下被实例化。创建静态内部类对象的具体语法格式如下,:,3.7,内部类,3.7.3,方法,内部类,方法,内部类是指在成员方法中定义的类,它只能在当前方法中被使用,。,例程,3-23,中,在,Outer,类的,test(),方法中定义了一个内部类,Inner,。由于,Inner,是方法内部类,因此程序只能在方法中创建该类的实例对象并调用,show(),方法。从运行结果可以看出,方法内部类也可以访问外部类的成员变量,num,。,3.8 Java,的帮助文档,3.8.1 Java,的文档注释,文档注释,用于,是,嵌入到程序当中的帮助信息,用于说明如何使用当前,程序,,它,以,“,/*,”开头,以“,*/,”标志结束,Java,中提供了,javadoc,命令,它可以将这些帮助信息提取出来,自动生成,HTML,格式的帮助文档,从而实现程序的文档,化,author,:用于对类的说明,表示这个程序的作者,version,:用于对类说明,表示这个程序的开发版本号,param,:用于对方法的说明,表示方法上定义的参数以及参数对应的说明,return,:用于对方法的说明,表示方法的返回值代表的意义,3.8 Java,的帮助文档,3.8.1 Java,的文档注释,为程序添加文档注释后,便可以使用,javadoc,命令生成,Person,类的帮助,文档,。,打开,命令行窗口,进入程序所在的目录,输入生成文档的命令,具体如下所示,:,其中:,-,d,用来指定输出文档存放的,目录,.,表示当前的,目录,-,version,用来指定输出文档中需包含版本信息,-,author,用来指定输出文档中需包含作者信息,3.8 Java,的帮助文档,3.8.2 JDK,帮助文档的使用,JDK,帮助文档是,Oracle,公司针对,JDK,中所有的,Java,类提供,的,一整套帮助文档,,它详细介绍了,所有,Java,类的属性、方法、继承关系和示例用法等内容,JDK,帮助文档通常有两种,一种是,Oracle,公司官方发布的,HTML,格式的,JDK,帮助文档,,一种是,由一些,Java,爱好者根据官方文档制作而成的,CHM,格式的,JDK,帮助文档,。,本章小结,本章详细介绍了,面向对象,的基础知识,,包括,什么是面向对象,、类和对象之间的关系、类的封装与使用、构造方法的定义与重载、,this,关键字、,static,关键字、内部类等,重点在于,面向对象的编程思想、类和对象、类的封装、构造方法以及,this,关键字的使用,,大家应该多思考,深刻领会面向对象的好处,熟练掌握好这些知识,有助于学习下一章的内容。深入理解面向对象的思想,对以后的实际开发也是大有裨益的,
展开阅读全文