《对象和类的进一步介绍包.ppt》由会员分享,可在线阅读,更多相关《对象和类的进一步介绍包.ppt(88页珍藏版)》请在三一办公上搜索。
1、第5章 对象和类的进一步介绍,抽象数据类型,绝大多数程序设计语言都预定义了一些基本数据类型,并相应定义了对那些类型的实例执行的操作。,概述,比如,对整型、实型等数值类型,有加、减、乘、除等操作,对逻辑类型,有逻辑与、逻辑或、逻辑非等操作。对于用户自定义的复合数据类型,需要由程序员自己定义一些方法,对该类型的实例进行所需的操作。,抽象数据类型,有些编程语言改进了这种处理方式,允许数据类型说明和欲对该类型变量进行操作的代码说明之间有较紧密的联系。通常把数据类型和对其进行的操作聚集在一起构成一种抽象数据类型。,抽象数据类型,严格地说,抽象数据类型是指基于一个逻辑类型的数据类型以及这个类型上的一组操作
2、。每一个操作由它的输入、输出定义。,示例,public class Date private int day,month,year;Date(int i,int j,int k)day=i;month=j;year=k;Date()day=1;month=1;year=1998;Date(Date d)day=d.day;month=d.month;year=d.year;,public Date tomorrow()Date d=new Date(this);d.day+;if(d.dayd.daysInMonth()d.day=1;d.month+;if(d.month 12)d.mont
3、h=1;d.year+;return d;,daysInMonth()返回每个月中不同的天数,抽象数据类型,在Java中把名为tomorrow的代码段叫做方法,也可以称为成员函数。Java在数据和操作间建立了较严格的联系,即把方法与数据封装在一个类中。,抽象数据类型,Data d=new Date(20,11,1998);/已初始化的date对象d.tomorrow();/tomorrow()方法作用于变量d要访问Date类的域,可使用点操作符“.”:d.day/d所指的Date对象中的day域,定义方法,在Java中,方法定义的一般格式如下:()是方法名,它必须使用合法的标识符。说明方法返回
4、值的类型。如果方法不返回任何值,它应该声明为void。Java对待返回值的要求很严格,方法返回值必须与所说明的类型相匹配。,定义方法,段可以含几个不同的修饰符。是传送给方法的参数表。表中各元素间以逗号分隔,每个元素由一个类型和一个标识符组成。表示方法体,是要实际执行的代码段。,示例1,void setName(String name)this.name=name;String getAddress()return address;,示例2,public class Date private int day,month,year;Date(int i,int j,int k)day=i;mont
5、h=j;year=k;Date()day=1;month=1;year=1998;Date(Date d)day=d.day;month=d.month;year=d.year;,public void printDate()System.out.print(day+/+month+/+year);public Date tomorrow()Date d=new Date(this);d.day+;if(d.day d.daysInMonth()d.day=1;d.month+;if(d.month 12)d.month=1;d.year+;return d;,public int daysI
6、nMonth()switch(month)case 1:case 3:case 5:case 7:case 8:case 10:case 12:return 31;case 4:case 6:case 9:case 11:return 30;default:if(year%100!=0,public static void main(String args)Date d1=new Date();System.out.print(The current date is(dd/mm/yy):);d1.printDate();System.out.println();System.out.print
7、(Its tomorrow is(dd/mm/yy):);d1.tomorrow().printDate();System.out.println();,Date d2=new Date(28,2,1964);System.out.print(The current date is(dd/mm/yy):);d2.printDate();System.out.println();System.out.print(Its tomorrow is(dd/mm/yy):);d2.tomorrow().printDate();System.out.println();,按值传送,Java只“按值”传送自
8、变量,即方法调用不会改变自变量的值。当对象实例作为自变量传送给方法时,自变量的值是对对象的引用,也就是说,传送给方法的是引用值。在方法内,这个引用值是不会被改变的,但可以修改该引用指向的对象内容。当从方法中退出时,所修改的对象内容可以保留下来。,程序3,public class PassTest float ptValue;public static void main(String args)String str;int val;PassTest pt=new PassTest();val=11;/给整型量val赋值 pt.changeInt(val);/改变val的值,创建类的实例,/va
9、l当前的值是什么呢?打印出来看看System.out.println(Int value is:+val);/给字符串str赋值str=new String(hello);/改变str的值pt.changeStr(str);/str当前的值是什么呢?打印出来看看System.out.println(Str value is:+str);/现在给ptValue赋值pt.ptValue=101f;/现在通过对象引用改值pt.changeObjValue(pt);,/当前的值是什么呢?System.out.println(Current ptValue is:+pt.ptValue);/修改当前值的
10、方法public void changeInt(int value)value=55;public void changeStr(String value)value=new String(different);public void changeObjValue(PassTest ref)ref.ptValue=99f;,this引用,在Java中,如果在类的成员方法中访问类的成员变量,可以使用关键字this指明要操作的对象。,示例,public class Date private int day,month,year;public void printDate()System.out.p
11、rintln(The current date is(dd/mm/yy):+this.day+/+this.month+/+this.year);,示例,public class Date private int day,month,year;public void printDate()System.out.println(The current date is(dd/mm/yy):+day+/+month+/+year);,数据隐藏,在Date类中说明day、month和year是private的,这意味着只能在Date类中的方法内访问这些成员,而在类外的方法中不能访问它们。,例5-4:,
12、public class DateUser public static void main(String args)Date mydate=new Date();mydate.day=21;,错误!,示例,Date d=new Date();d.day=32;/语法正确但语义错误d.month=2;d.day=30;/没有进行月份的循环检查 d.month=d.month+1;上述赋值语句的结果使得日期对象中的域值成为非法的,或称为不一致的。,说明,如果类的数据成员没有明确地提供给使用者访问,就是说它不是公有的,则类的使用者必须通过方法来访问成员变量。,示例,public void setDa
13、y(int targetDay)if(targetDay this.daysInMonth()System.err.println(invalid day+targetDay);else this.day=targetDay;,封装,如果对数据的访问是完全放开的,那么,程序会变得混乱且不易控制。对于其他复杂的数据类型,类的使用者可能会疏忽对数据的一致性检查。,封装,封装是面向对象方法的一个重要原则。它有两个基本涵义:一是指对象的全部属性数据和对数据的全部操作结合在一起,形成一个统一体,也就是对象;另一方面是指,尽可能地隐藏对象的内部细节,只保留有限的对外接口,对数据的操作都通过这些接口实现。,
14、重载方法名,如果需要在同一类中写多个方法,让它们对不同的变量进行同样的操作,就需要重载方法名。在Java和其他几种面向对象的程序设计语言中,允许对多个方法使用同一个方法名,这就是方法名的重载。当然,前提条件是能够区分实际调用的是哪个方法,才可用这种方式。,重载方法名,Java根据参数自变量的类型及参数的个数来区分这些方法。例如:public void print(int i)public void print(float f)public void print(String s)当调用print方法时,可根据自变量的类型选中相应的一个方法。,重载方法规则一,调用语句的自变量列表必须足够判明要调
15、用的是哪个方法。自变量的类型可能要进行正常的扩展提升(如浮点变为双精度),但在有些情况下这会引起混淆。,重载方法规则二,方法的返回类型可能不同。如果两个同名方法只有返回类型不同,而自变量列表完全相同则是不够的,因为在方法执行前不知道能得到什么类型的返回值,因此也就不能确定要调用的是哪个方法。重载方法的参数表必须不同,即参数个数或参数类型不同。,对象的构造和初始化,在说明了引用后,要调用new为新对象分配空间。在调用new时,既可以带有变量,也可以不带变量。系统根据所带参数的个数和类型,调用相应的构造方法。,对象的构造和初始化,调用构造方法时,步骤如下:(1)分配新对象的空间,并进行默认的初始化
16、。在Java中,这个过程是不可分的,从而可确保不会有没有初值的对象。(2)执行显式的成员初始化。(3)执行构造方法,构造方法是一个特殊的方法。,显式成员初始化,在成员说明中写有简单的赋值表达式,就可以在构造对象时进行显式的成员初始化。,示例,public class Initialized private int x=5;private String name=Fred;private Date created=new Date();/成员的访问方法.,构造方法,显式初始化是为对象域设定初值的一种简单方法。因为设定的初值不具有变化性,所以这种简单的方法有其局限性。系统定义了构造方法,同时允许程
17、序员编写自己的构造方法完成不同的操作。,构造方法,构造方法是特殊的类方法,有着特殊的功能。它的名字与类名相同,没有返回值,在创建对象实例时由new运算符自动调用。为了创建实例的方便,一个类可以有多个具有不同参数列表的构造方法,即构造方法可以重载。,示例,public class Xyz/成员变量int x;public Xyz()x=0;public Xyz(int i)x=i;,使用参数创建对象,创建对象,构造方法,因为构造方法的特殊性,它不允许程序员按通常调用方法的方式来调用。构造方法不能说明为native,abstract,synchronized或final,也不能从父类继承构造方法。
18、,默认构造方法,每个类都至少有一个构造方法。如果程序员没有为类定义构造方法,系统会自动为该类生成一个默认的构造方法。默认构造方法的参数列表及方法体均为空。,默认构造方法,如果程序员定义了一个或多个构造方法,则自动屏蔽掉默认构造方法。构造方法不能继承。如果程序员定义了构造方法,那么,最好包含一个参数表为空的构造方法。,finalize方法,finalize方法属于Object类,它可被所有类使用。如果对象实例不被任何变量引用时,Java会自动进行“垃圾回收”,收回该实例所占用的内存空间。,finalize方法,在对对象实例进行垃圾收集之前,Java自动调用对象的finalize方法,它相当于C+
19、中的析构方法,用来释放对象所占用的系统资源。,finalize方法,finalize方法的说明方式如下:protected void finalize()throws Throwable,子类“is a”关系,例public class Employee private String name;private Date hireDate;private Date dateOfBirth;private String jobTitle;private int grade;.,public class Manager private String name;private Date hireDat
20、e;private Date dateOfBirth;private String jobTitle;private int grade;private String department;private Employee subordinates;.,“is a”关系,Manager类和Employee类之间存在重复部分。实际上,适用于Employee的很多方法可能不经修改就会被Manager所使用。Manager与Employee之间存在“is a”关系,即Manager“is a”Employee。,extends关键字,面向对象的语言提供了派生机制,它允许程序员用以前已定义的类来定义一
21、个新类。新类称作子类,原来的类称作父类或超类。两类中公共的内容放到父类中。Java中亦有同样的机制。在Java中,用关键字extends表示派生。,例5-10:,public class Employee private String name;private Date hireDate;private Date dateOfBirth;private String jobTitle;private int grade;.public class Manager extends Employee private String department;private Employee subord
22、inates;.,extends关键字,派生机制改善了程序的可维护性,增加了可靠性。对父类Employee所做的修改延伸至子类Manager类中,而程序员不需做额外的工作。,单重继承,如果一个类有父类,则其父类只能有一个,Java只允许从一个类中扩展类。这条限制叫单重继承。为了保留多重继承的功能,Java提出了接口的概念。虽然一个子类可以从父类继承所有的方法和成员变量,但它不能继承构造方法。,单重继承,只有两种方法可让一个类得到一个构造方法,一种方法是自己编写一个构造方法,另一种方法是,因为用户没有写构造方法,所以系统为类提供唯一一个默认的构造方法。,多态性,对象是多态的,即它们有“许多形式”
23、。在Java中,有一个很特殊的类,它是所有类的父类,这就是类。例:public class Employee extends Object,方法的参量和异类集合,1.方法的参量实际中,实例和变量并不总是属于同一类。例public TaxRate findTaxRate(Employee e)/进行计算并返回e的税率/而在应用程序类中可以写下面的语句Manager m=new Manager();TaxRate t=findTaxRate(m);,这是合法的,因为Manager是一个Employee。,2.异类集合,异类集合是由不同质内容组成的集合。在面向对象的语言中,可以创建有公共祖先类的任何
24、元素的集合。,2.异类集合,例:Employee staff=new Employee1024;staff0=new Manager();staff1=new Employee();,2.异类集合,数组staff中各元素的类型是不相同的。因为Java中每个类都是Object的子类,所以可以使用Object的一个数组作为任何对象的容器。由于简单变量不是对象,因此不能加到Object数组中。,instanceof运算符,由于类的多态性,类的变量既可以指向本类实例,又可以指向其子类的实例。可以通过instanceof运算符来判明一个引用到底指向哪个实例。,instanceof运算符,假定继承关系如下
25、所示:public class Employee extends Objectpublic class Manager extends Employeepublic class Contractor extends Employee,instanceof运算符,则类之间的层次关系如下图所示:,示例,public void method(Employee e)if(e instanceof Manager)/经理级人士else if(e instanceof Contractor)/掌握公司机密的高层人士else/普通雇员,转换对象,Java允许使用对象之父类类型的一个变量指示该对象。,下面的语
26、句是合法的:Employee e=new Manager();使用变量e,可以只访问Employee对象的内容,而隐藏Manager对象中的特殊内容。,转换对象,对象引用的赋值兼容原则允许把子类的实例赋给父类的引用,但不能把父类的实例赋给子类的引用。如果用instanceof运算符已判明父类的引用指向的是子类实例,就可以转换该引用,恢复对象的全部功能。,示例,public void method(Employee e)if(e instanceof Manager)Manager m=(Manager)e;System.out.println(This is the manager of+m.
27、department);/其他操作,转换对象,一般地,要替换对象引用时需做下列检查:(1)沿类层次向“上”转换总是合法的。实际上此种方式下不需要转换运算符,只用简单的赋值语句就可完成。(2)对于向“下”替换,只能是父类到子类转换,其他类之间是不允许的。(3)编译器检查正确后,需在运算时检查引用类型,覆盖方法,使用类的继承关系,可以从已有的类产生一个新类,修改父类中已有的方法。如果子类中定义方法所用的名字、返回类型和参数表和父类中方法使用的完全一样,称子类方法覆盖了父类中的方法,即子类中的成员方法将隐藏父类中的同名方法。,覆盖方法,利用方法隐藏,可以重定义父类中的方法。覆盖的同名方法中,子类方法
28、不能比父类方法的访问权限更严格。在子类中,若要使用父类中被隐藏的方法,可以使用super关键字。,示例,class Point void print()System.out.println(This is the superclass!);public static void main(String args)Point superp=new Point();superp.print();Point3d subp=new Point3d();subp.print();class Point3d extends Point void print()System.out.println(This
29、is the subclass!);,示例,class Point1 void print()System.out.println(This is the superclass!);public static void main(String args)Point1 superp=new Point1();superp.print();Point3d subp=new Point3d();subp.print();class Point3d extends Point1 void print()System.out.println(This is the subclass!);super.pr
30、int();,示例,public class Employee String name;int salary;public String getDetails()return Name:+name+“n+Salary:+salary;public class Manager extends EmployeeString departemnt;public String getDetails()return Name:+name+“n+Manager of+department;,覆盖方法,子类中的方法替换或称隐藏了原来的方法。假定说明了如下两个实例:Employee e=new Employe
31、e();Manager m=new Manager();此时,e.getDetails()与m.getDetails()将执行不同的代码。前者是Employee对象,将执行Employee类中的方法,后者是Manager对象,执行的是Manager类中的方法。,示例,class Point/其他构造方法public double distance()return Math.sqrt(x*x+y*y);/其他的成员方法static void main(String args)Point p=new Point(1,1);System.out.println(p.distance()=+p.dis
32、tance();p=new Point3d(1,1,1);System.out.println(p.distance()=+p.distance();,class Point3d extends Pointpublic double distance()return Math.sqrt(x*x+y*y+z*z);,程序执行的结果为:p.distance()=1.414213562p.distance()=1.732050808,Java包,为了更好地组织类,Java提供了包机制。包是类的容器,用于分隔类名空间。Java中的包一般均包含相关的类。程序员可以使用package指明源文件中的类属于哪
33、个具体的包。,Java包的概念,包语句的格式为:package pkg1.pkg2.pkg3.;程序中如果有package语句,该语句一定是源文件中的第一条可执行语句,它的前面只能有注释或空行。一个文件中最多只能有一条package语句。,Java包的概念,包的名字有层次关系,各层之间以点分隔。包层次必须与Java开发系统的文件系统结构相同。通常包名中全部用小写字母。,Java包的概念,当使用包说明时,程序中无需再引用(import)同一个包或该包的任何元素。import语句只用来将其他包中的类引入当前名字空间中。而当前包总是处于当前名字空间中。例:package java.awt.image
34、;则此文件必须存放在Windows的javaawtimage目录下或unix的java/awt/image目录下。,import语句,在Java中,使用引入(import)语句告诉编译器要使用的类所在的位置。包名也是类名的一部分。例如,如果abc.FinanceDept包中含有Employee类,则该类可称作abc.FinanceDept.Employee。引入语句的格式如下:import pkg1.pkg2.pkg3.(类名|*);,示例,假设有一个包a,在a中的一个文件内定义了两个类xx和yy,其格式如下:package a;class xx.class yy.,当在另外一个包b中的文件z
35、z.java中使用a中的类时,语句形式如下:/zz.javapackage b;import a.*;class zz extends xx yy y;.,import语句,要引入所有类时,可以使用通配符“*”,如:import java.lang.*;引入整个包时,可以方便地访问包中的每一个类。后果:会占用过多的内存空间,而且代码下载的时间将会延长。建议:在了解了包的基本内容后,实际用到哪个类,就引入哪个类,尽量不造成资源的浪费。,目录层次关系及CLASSPATH环境变量,包“存放”在包名构成的目录中。在CLASSPATH中必须加入目录层次中的根abc。如果程序员想访问其他地方放置的包,则必须显式设置CLASSPATH变量。,目录层次关系及CLASSPATH环境变量,如果在编译命令中使用-d选项,则Java编译器可以创建包目录,并把生成的类文件放到该目录中。例:%javac-d/home/anton/mypackages/Employee.java,目录层次关系及CLASSPATH环境变量,CLASSPATH环境变量必须包含包路径:CLASSPATH=/home/anton/mypackages;由此,编译器能找到前例中Manager.java文件中的abc.FinanceDept.Employee类的所在位置。,