Java教材课件05Java面向对象程序设计.ppt
1,第5章 Java面向对象程序设计,2,教学目的要求,理解java语言的面向对象技术,包括面向对象的基本概念、面向对象的程序设计方法;理解java中的类、包、对象、抽象类、接口和面向对象的特性;掌握Java语言中类、方法和接口的基本定义及使用方法;了解包的概念及打包和引入方法;通过技能实训,掌握一般Java程序的面向对象编程方法,达到熟练开发Java一般程序的目的。,3,本章内容,5.1 类5.2 访问控制符与封装5.3 继承5.4 非访问控制符接口5.5 Java的名字空间和包5.6 接口,4,5.1 类,面向对象回顾5.1.1 类的定义 5.1.2 类的使用5.1.3 方法重载5.1.4 内部类,5,面向对象回顾(1)-基本思想,面向对象的基本思想面向对象是一种新兴的程序设计方法,或者是一种新的程序设计规范(paradigm),其基本思想是使用对象、类、继承、封装、消息等基本概念来进行程序设计。从现实世界中客观存在的事物(即对象)出发来构造软件系统,并且在系统构造中尽可能运用人类的自然思维方式。开发一个软件是为了解决某些问题,这些问题所涉及的业务范围称作该软件的问题域。其应用领域不仅仅是软件,还有计算机体系结构和人工智能等。,6,面向对象回顾(1)-基本思想,1 对象的基本概念对象是系统中用来描述客观事物的一个实体,它是构成系统的一个基本单位。一个对象由一组属性和对这组属性进行操作的一组服务组成。主动对象是一组属性和一组服务的封装体,其中至少有一个服务不需要接收消息就能主动执行(称作主动服务)。2 类的基本概念 类是具有相同属性和服务的一组对象的集合,它为属于该类的所有对象提供了统一的抽象描述,其内部包括属性和服务两个主要部分。在面向对象的编程语言中,类是一个独立的程序单位,它应该有一个类名并包括属性说明和服务说明两个主要部分。3 消息 消息就是向对象发出的服务请求,它应该包含下述信息:提供服务的对象标识、服务标识、输入信息和回答信息。服务通常被称为方法或函数。,7,面向对象回顾(2)-基本特性,1封装性封装性就是把对象的属性和服务结合成一个独立的相同单位,并尽可能隐蔽对象的内部细节,包含两个含义:把对象的全部属性和全部服务结合在一起,形成一个不可分割的独立单位(即对象)。信息隐蔽,即尽可能隐蔽对象的内部细节,对外形成一个边界或者说形成一道屏障,只保留有限的对外接口使之与外部发生联系。封装的原则在软件上的反映是:要求使对象以外的部分不能随意存取对象的内部数据(属性),从而有效的避免了外部错误对它的交叉感染,使软件错误能够局部化,大大减少查错和排错的难度。,8,面向对象回顾(2)-基本特性,2继承性特殊类的对象拥有其一般类的全部属性与服务,称作特殊类对一般类的继承。一个类可以是多个一般类的特殊类,它从多个一般类中继承了属性与服务,这称为多继承。在java语言中,通常我们称一般类为父类(superclass,超类),特殊类为子类(subclass)。3多态性对象的多态性是指在一般类中定义的属性或服务被特殊类继承之后,可以具有不同的数据类型或表现出不同的行为。这使得同一个属性或服务在一般类及其各个特殊类中具有不同的语义。例如:几何图形的绘图方法,椭圆和多边形都是几何图的子类,其绘图方法功能不同。,9,面向对象回顾(3)-面向对象方法学,OOAObject Oriented Analysis 面向对象的分析OODObject Oriented Design 面向对象的设计OOIObject Oriented Implementation 面向对象的实现,10,5.1.1 类的定义,类是java中的一种重要的复合数据类型,是组成java程序的基本要素。它封装了一类对象的状态和方法,是这一类对象的原形。一个类的实现包括两个部分:类声明和类体 1类声明:类声明中包括关键字Class,类名及类的属性。类声明的格式如下:classextendsimplements,11,同时,在类声明中还可以包含类的父类(超类),类所实现的接口以及修饰符public、abstract或final,这些内容将在后面的几节中分别介绍。由类定义可知,类定义包括关键词class、类名和类的属性。类名是Java语言合法的标识符,类名一般具有一定的含义。(1)类定义修饰符类的说明性修饰符说明类的性质和访问权限,包括public、缺省修饰符、abstract、final。关于修饰符具体含义后面详细介绍。(2)extendsextends说明类的父类,一般形式为extends父类名Java语言中,如果在类说明中无extends,则隐含地假设其父类为类。,12,5.1.1 类的定义,2类主体类主体是是Java类的主体部分,完成变量的说明以及方法的定义及实现。在类中,用变量来说明类的状态,而用方法来实现类的行为。包含类主体的类结构如下:通常变量在方法前定义(并不一定要求),Java语言中没有独立的函数和过程,所有的子程序都是作为类方法定义的。如下所示:classclassNamememberVariableDeclarationsmethodDeclarations,13,5.1.1 类的定义,3成员变量成员变量的声明方式如下:public|protected|private static final transient volatile typevariableName;/成员变量其中,static:静态变量(类变量);相对于实例变量final:常量transient:暂时性变量,用于对象存档,用于对象的串行化,见对象的串行化一节volatile:贡献变量,用于并发线程的共享,14,5.1.1 类的定义,4成员方法说明成员方法定义的一般形式为:方法修饰符()方法体方法说明是指出方法返回类型、方法名、访问权限和入口参数。方法修饰符成员方法修饰符主要有public、private、protected、final、static、abstract和synchronized共7种,前3种的访问权限、说明形式和含义与成员变量一致。修饰符说明详见5.2、5.4节。方法的返回值类型Java语言要求在成员方法说明中必须指明方法返回值的类型,返回值的类型为Java语言的任何数据类型。如果一个成员方法不需要返回值,则其返回值的类型被说明为void。方法返回值用return语句来实现,如果有返回值,那么return语句要带参数,并且return语句中返回的数据类型必须与方法说明中的方法返回值的类型一致。,15,方法名成员方法名是Java语言合法的标识符,为了提高程序的可读性,成员方法名一般具有一定的含义。参数列表成员方法的参数列表是由逗号分隔的类型及参数名组成,是可选项。类型可以是Java语言的任何数据类型。方法体方法体是一个方法定义的主要部分,包含了所有实现方法功能的Java语言程序代码。在方法体中可以定义局部变量,它的作用域仅在方法体内,当方法被执行结束之后,该方法内部的所有局部变量也就失效了,局部变量不能与参数列表中参数名同名。方法体用“”括起来。,16,【例5-2】定义一个方法,方法功能为根据参数r的大小,返回圆的面积。在类中赋参数r,并且输出面积值。public class Li5_02public static void main(String args)double k;Li5_02 mj=new Li5_02();k=mj.area(5);System.out.println(k);public double area(int r)/定义area方法,带有一个参数final double PI=3.14;/定义常量PI,并赋初值3.14return PI*r*r;/根据r的值,计算面积后,返回面积值 运行结果为:78.5,17,5.1.1 类的定义,5.构造方法构造方法是一种特殊的方法,主要用于为类的方法中变量赋初始值的功能。当用new创建一个类的新的对象时,构造方法就立即执行。构造方法名字必须与类名相同。除了构造方法,在类中不能出现与类名相同的方法。构造方法的语法为:public 类名(参数列表)语句序列;Java语言中每个类都有构造方法,如果一个类中没有说明该类的构造方法,则系统将提供隐含的不带任何参数的构造方法,这个空的构造方法其实什么也不做。一旦我们定义了自己的构造方法,Java编译器就不再添加这种缺省的构造方法。,18,5.1.1 类的定义,构造方法的特点:构造方法没有返回值类型,甚至没有void。其修饰符只能是访问控制修饰符,即public、private、protected中的任一个。构造方法不能从父类中继承。构造方法可以重载,一个类可以有任意多个构造方法。不同的构造方法根据参数的不同状态来选择合适的构造方法。构造方法不能直接通过方法名引用,必须通过new运算符。在构造方法中可以调用当前类和其父类的另一个构造方法,但必须是方法体的第一条语句。使用当前类的构造方法用this来引用,使用其父类的构造方法用super来引用。,19,5.1.2 对象的使用,5.1.2.1 对象创建在Java语言中,一个Java对象是类的一个实例,创建一个对象就是创建类的一个实例,对象即类的实例化。new运算符用于创建一个类的实例并返回对象的引用。对象创建包括对象声明,实例化和初始化三方面的内容。一般格式为:type 对象名=new type(参数列表);其中type为引用组合类型(包括类和接口)。该格式声明了一个类型为type的对象。对象的声明并不为对象分配内存空间。用运算符new为对象分配内存空间,实例化一个对象。比如:String UserName=new String(“zhangsan”);,20,5.1.2 对象的使用,5.1.2.2 对象使用对象的使用包括引用对象的成员变量和方法,通过运算符“”可以实现对实例变量的访问和实例方法的调用,变量和方法还可以设定一定的访问权限来允许或禁止其他对象对它的访问。通常有两种途径来使用对象:1.引用对象中的变量引用对象的变量的一般形式为:.2.引用对象中的方法引用对象中的方法的一般形式为:.()其中,参数列表是可选项。在进行对象方法的引用时,方法中参数的个数、参数的数据类型与原方法中定义的要一致,否则编译时会出错。,21,5.1.2 对象的使用,5.1.2.3 对象数组前面已经讲过,数组的元素不仅可以是基本数据类型,也可以是对象。在实际应用中,更普遍的可能是数组元素是对象的对象数组了。下面用CCircle类作为例子介绍对象数组的创建和使用。如果定义CCircle类(见例5.4源程序),那么,如何来创建和操纵CCircle类的对象的一个数组呢?实际上,对象数组的创建与基本数据类型的数组是一样的,分两步进行:1.声明类类型的数组变量,并用new分配内存空间给数组;2.用new产生新的对象,并分配内存空间给它。,22,5.1.2 对象的使用,5.1.2.4 对象释放如前所述,用new来创建新的对象,此时Java便会分配内存空间给它。如果此对象不在使用了,Java一样可回收它所占的内存空间。其作法是,把指向该对象的值设置为null。该对象便成了无用对象,Java系统通过垃圾回收器GC(Garbage Collector)周期性地释放无用对象所使用的内存,完成对象的清除工作。同样当对象数组中的对象不在使用时,可以先把对象数组中的元素置上null,然后让Java内存垃圾回收器自动回收。当不存在着对一个对象的引用时,该对象就成为一个无用对象。GC自动扫描对象的动态内存区,对被引用的对象添加标记,然后把没有引用的对象作为垃圾收集起来并加以释放。GC在Java中作为一个线程来运行的,即调用System.gc(),当要求垃圾收集时,该线程与系统同步运行;否则在系统空闲之时异步地运行。此外,在Java系统开始运行时,会自动调用一个名为finalize()方法,使它清除对象所占的内存。比C+中用delete和C中用free来释放内存的措施好得多。,23,5.1.3 方法重载,在Java类中可以创建名字相同,但是参数不同和返回值不同的几个方法,这就是方法重载(overloading),Java系统通过参数和返回值来分辨具体是哪一个方法。通过方法重载,一个类中可以有多个具有相同名字的方法,传递给它们的不同个数和类型的参数来决定使用那种方法,这就是多态。构造方法是一种特殊的方法。Java中的每个类都有构造方法,用来初始化该类的一个新的对象。在构造方法的实现中,为了实现不同对象的不同初始化值,也可以进行方法重载,所以类可以有多个构造方法,并且它们共享同一个名字,构造方法可以通过参数的类型和数目区分。构造方法使用它的参数初始化新对象的状态,当创建对象时,应该选择其参数最能反映所初始化的新对象的构造方法,根据传给构造方法的参数数目和类型的不同,Java编译器可以决定使用那个构造方法。,24,内部类 在类内部可定义成员变量和方法,其实,在类内部也可以定义另一个类。如果在类A的内部再定义一个类B,此时类B称为内部类,而类A则称为外部类。内部类可声明为public或private。当内部类声明成public或private时,其访问限制与成员变量或方法完全相同。关于内部类的用法详见第8章8.3节。,5.1.4 内部类,25,5.2 访问控制符和封装,前已述及,Java的类成员主要有访问修饰符:private、protected、public和default,具体存取权限见表5-1。表5-1 不同访问修饰符的具体存取权限,26,5.3 继承,5.3.1 子类和简单继承举例按定义为类的格式,如果有如下类A声明:class 类名A extends 父类Bimplements则说明新定义的类A是父类B的子类。如果缺省extends子句,则该类为的子类。子类可以继承父类中访问权限为public、protected等的成员变量和方法,但不能继承访问权限为private的成员和方法。有了继承机制,在编写程序时,就可以先定义一个包含公共变量和公用方法的类作为父类,再在此基础上创建具有专用变量和专用方法的子类。子类一方面继承父类中已有的变量和方法(普遍性原则),另一方面子类还可以增加父类中所没有的变量和方法(特殊性原则)。,27,5.3 继承,5.3.2 变量隐藏和方法覆盖 子类继承父类后,如果出现子类的成员变量和父类的成员变量同名,那么子类将把父类的成员变量隐藏起来。在这种情况下,子类使用的变量是它自己的变量,而不是父类的成员变量,那么子类如果要调用父类的变量,则必须借用下一小节要阐述的关键字super。另外一种情况是子类的方法名与父类的方法名相同(返回值的类型和入口参数的数目、类型均相同),那么在子类中重新改写了父类的同名方法,即子类方法覆盖(overriding)了父类的方法。通过方法重写,子类可以重新实现父类的某些方法,使其具有自己的特征。方法覆盖与重载均是Java多态的技巧之一,但两者之间也有不同之处:重载:英文名称为overloading,意指在同一个类中,定义多个名称相同,但参数个数或类型不同的方法,Java根据参数的个数或类型,调用相对应的方法。覆盖:英文名称为overriding,是指在子类中,定义名称、参数个数与类型均与父类相同的方法,用以改写父类中的方法的功能。,28,5.3.3 super和this在Java中,执行子类的构造方法之前或子类没有明确地指定构造方法,会自动调用父类中没有参数的构造方法,其目的是为了帮助继承自父类的成员变量做初始化操作。问题是,如果父类有多个构造方法,如何才能调用父类中特定的构造方法呢?如果在子类中还需要用到父类中被隐藏的变量或者被覆盖了的方法,该怎么办呢?Java提供了关键字super来实现对父类的成员和方法的访问。Super有三种情况可以使用:用来访问父类中被覆盖的方法;用来调用父类中的构造方法;用来访问父类中被隐藏的成员变量。,5.3 继承,29,5.3 继承,调用构造方法遵循以下的几条规则:当一个类创建对象时,可以调用该类的父类的构造方法。调用父类的构造方法很简单,只要在类的构造方法的方法体中,第一条为super语句就可以了。super可以调用父类的任何一个带入口参数或不带入口参数的构造方法。如果一个类的构造方法中第一条语句没有用super来调用父类的构造方法,则编译器也会默认在构造方法中用super()语句调用父类的无参构造方法。如果某个类的构造方法的第一条语句是用this来调用本类的另外一个构造方法,那么Java系统就不会默认这个构造方法调用父类的构造方法。一个构造方法是用this语句调用本类的另一个构造方法时,如果被调用的构造方法又是调用父类的构造方法而又没有用super语句,那么编译器会默认它含有super()语句。此时,父类中若不存在无参的构造方法,也将会导致编译出错。,30,5.3 继承,5.3.4 运行时多态与多重继承Java中每一种操作,操作数据的类型必须合法。父类有的方法子类都有,凡是能够使父类生成对象的地方,都可以使用子类生成对象。运行时多态有以下两条规则:对子类的一个实例,如果子类重写(覆盖)了父类的方法,则运行时系统就调用子类的方法。如果子类继承了父类的方法,则运行时系统就仍调用父类的方法。,31,5.3.5 对象类型转换前面已经讲过基本数据类型的转换,实际上Java中两个不同类型对象之间也可以转换,不过有个限制:两个转换的对象之间应该具有继承关系,也就是说只是在子类和父类的对象之间进行转换,而不是任意两个类。一个子类对象的类型可以向上转换成它的父类类型,这个转换过程是安全的。因为父类所具有的信息,子类一般全有。当然,转换过程中会丢失属于子类而不属于父类的信息。其中大学生和研究生是学生的子类。按照前面所说的原则,以下转换过程是安全的:UndergraduateStudent anUGS=new UndergraduateStudent();Student aStudent=(Student)anUGS;但是反过来,一个父类对象的类型未必可以向下转换成子类的对象的类型,因为子类具有的信息,父类未必包含。所以只有当父类对象实际上是子类的一个实例的时候,才可以转换,否则不能进行这种转换。,32,5.3 继承,5.3.6 抽象类Java也可以创建专门的类用来当作父类,这种类称为抽象类(abstract class)。抽象类有点类似“模板”的作用,其目的是要你根据它的格式来修改并创建新的类。不能够通过抽象类直接创建对象,只能通过抽象类派生的新的类,再由新类创建对象。定义一个抽象类的格式为:abstract class 类名称声明数据成员;返回值的数据类型 方法名称(参数列表)定义普通的方法 abstract返回值的数据类型 方法名称(参数列表);/定义抽象的方法注意:在抽象类中,方法的定义可分为两种:一种是普通方法;另一种是抽象方法,此方法以abstract开头,且只声明了返回值的数据类型、方法名称、所需参数,但没有方法体。这样,抽象方法中的处理方式必须在子类中完全实现。,33,5.4 非访问控制符,5.4.1 static在类中声明一个变量或方法时,还可以指定它为实例成员或类成员。其格式为:static 类型 变量名;static 返回值类型 方法名(参数列表)上述用static修饰的变量和方法分别称为类变量和类方法,也称静态变量和静态方法。如果没有static修饰,则分别称为实例变量和实例方法。,34,5.4 非访问控制符,5.4.2 final从安全性和面向对象程序设计上考虑,一些类不希望被继承,可以用final关键字来修饰。下列情况通常某些类被定义为final类:定义为final类通常是一些有固定作用,用来完成某种标准功能的类。例如,Java中的String类,它对编译器与解释器的正常运行有很重要的作用,所以被修饰为final类。如果认为一个类的定义已经很完美,不需要再生成它的子类时,就说明为final类。有些方法不能被重写(覆盖),也把它限定为final方法。格式为:final 返回值类型 方法名(参数列表)注意:abstract和final不能同时修饰一个类。可用final来作为常量的修饰符。一个类的成员变量也可以被修饰成final,一旦定义为final,则它的值在整个程序执行过程中都不会改变。,35,5.4 非访问控制符,5.4.3 volatile、native、synchronized用volatile修饰的成员变量称为易失变量,通常这个变量同时被几个线程控制和修改,也就是说,这个成员变量不仅被当前程序所掌握,在运行过程可能存在其他未知的程序操作来影响和改变该变量的取值。用native修饰的是一种特殊方法,一般用来声明用其他语言编写的方法体并具体实现方法功能。由于native的方法是用其他语言在外部编写,所以,所有的native方法都没有方法体,而使用一个“;”代替。如果用synchronized修饰一个类方法,那么在调用执行前,将把系统类中对应的当前类的对象加锁。如果用synchronized修饰一个对象方法,那么在调用执行前,将把当前对象加锁。synchronized主要用于多线程共存的程序中的协调与同步,详见多线程一章部分。,36,5.5 Java的名字空间和包,5.5.1 Java的名字空间Java注意解决名字空间的冲突问题,全局变量不再是语言的组成部分,即没有全局的方法,也没有全局的变量。所有的变量和方法都是在类中定义,并且是类的重要组成部分,而每个类又是包的一部分,因此每个Java变量或方法都可以用全限定的名字表示。包括包名、类名、域名三部分,之间用“.”分隔。Java编译器将Java程序的每个类的编译代码,即字节码放在不同的文件中,这些编译代码文件名与类同名,但加上扩展名(.class),因此一个包含有多个类定义的源文件编译后有多个.class文件。Java源代码的扩展名一般为.java,其中包括一个或多个类定义,如果在Java文件中有多个类定义,则只能有一个类可以定义为public,并且这个类的名字必须与程序的源代码名(去掉扩展名)一致。,37,5.5 Java的名字空间和包,5.5.2 Java提供的包JDK提供了100多个公共包,常用的有以下Java包:1.Java.lang:提供利用Java编程语言进行程序设计的基础类,比如Object类、String类、StringBuffer类、System类、Reader类、Writer类等等。2.java.io:通过数据流、序列化和文件系统提供系统输入和输出。3.java.util:包含集合框架、事件模型、日期和时间设施、国际化和各种实用工具类。如Calendar(日历)类、Vector(向量)类等等。4.java.awt、javax.swing:包含了一些用来建立图形界面的类。比如Window类、Button类、Menu类、Color类、Graphics类等等。5.java.awt.image:提供创建和修改图像的各种类。如BufferedImage类、ColorModel类等等。6.java.applet:包含用于执行小程序的类,比如Applet类。:包含一些网络访问功能的类,例如ServerSocket类、Socket类、URL类等等。8.java.sql:包含访问数据库资源的类,如SQLPermission 类、DriverManager类等等。9.sun.tools.debug:该软件包是SUN公司提供给Java用户的调试工具包,它包含各种用于调试类和接口的工具。,38,5.5 Java的名字空间和包,5.5.3 自定义包 除了使用Java提供的包以外,每个程序员都可以也应该把自己编写的类分门别类的装在不同的包中。Java的源程序格式在前面已经说过,如果这个源程序开头有:package pack1;说明该程序所定义的类属于pack1这个包。一般格式为:package pack1.pack2.pack3;这些包所放的位置应使编译程序方便找到用户定义的包。有一个简便的方法,即包名和它们的结构应该恰好同目录(文件夹)相对应,每个包对应于当前目录下的一个与包同名的目录,子包的类存在于相应的子目录中。,39,5.6 接口,接口(interface)是Java所提供的另一种重要功能,它的结构和抽象类非常相似。接口是一种特殊的类,但接口与类存在着本质的区别。类有它的成员变量和成员方法,而接口却只有常量和抽象方法,也就是说接口的成员变量必须初始化,同时接口中的所有方法必须全部声明为abstract方法,一个类可以有多个接口。Java语言通过接口使得处于不同类甚至互不相关的类具有相同的行为。,40,5.6 接口,5.6.1 接口的声明接口通过关键词interface来定义,接口定义的一般形式为 接口修饰符 interface接口名extends父类接口列表/接口体接口修饰符:接口修饰符为接口访问权限,有public和缺省两种状态。public状态用public指明任意类均可以使用这个接口。缺省状态在缺省情况下,只有与该接口定义在同一包中的类才可以访问这个接口,而其他包中的类无权访问该接口。接口名:接口名为合法的Java语言标识符。父类接口列表:一个接口可以继承其他接口,可通过关键词extends来实现,其语法与类的继承相同。被继承的类接口称为父类接口,当有多个父类接口时,用逗号“,”分隔。接口体:接口体中包括接口中所需要说明的常量和抽象方法。由于接口体中只有常量,所以接口体中的变量只能定义为static和final型,在类实现接口时不能被修改,而且必须用常量初始化。接口体中的方法说明与类体中的方法说明形式一样,由于接口体中的方法为抽象方法,所以没有方法体。抽象方法的关键字abstract是可以省略的,同时成员变量的final也可省略。接口体中方法多被说明成public型。,41,5.6 接口,5.6.2 接口的实现在前面所介绍的类声明中,用implements子句表示一个类用于实现某个接口。一个类可以同时实现多个接口,接口之间用逗号“,”分隔。在类体中可以使用接口中定义的常量,由于接口中的方法为抽象方法,所以必须在类体中加入要实现接口方法的代码,如果一个接口是从别的一个或多个父接口中继承而来,则在类体中必须加入实现该接口及其父接口中所有方法的代码。在实现一个接口时,类中对方法的定义要和接口中的相应方法的定义相匹配,其方法名、方法的返回值类型、方法的访问权限和参数的数目与类型信息要一致。,42,5.6 接口,5.6.3 接口的使用 5.6.4 扩展接口与接口的多重继承与类一样,可以使用extends子句、扩展接口,生成子接口。原来的接口称为基本接口(base interface)或父接口(super interface),扩展出的接口称为派生接口或子接口。通过这种机制,派生接口不仅可以保有父接口的成员,同时也可以加入新的成员以满足实际问题的需要。与类不同的是,一个接口可以扩展多个接口,继承它们所有属性,而一个类只能扩展一个类。显然,接口不能扩展类,接口的方法必须全是抽象的。例如:interface A extends B这条语句表示定义了接口A并继承了接口B,使A成为B的子接口,并且A具有B的所有属性。,