1、Java面向对象特性,目标,熟悉类的概念,以及用对象对类进行实例化的概念。 学会如何在Java中定义类。 学会在Java中定义并使用方法(对象的动作)。 学会在Java中创建对象。 学习信息隐藏与封装的相关知识。 了解面向对象的程序设计。,抽象数据类型,绝大多数程序设计语言都预定义了一些基本数据类型,并相应定义了对那些类型的实例执行的操作。,概述,比如,对整型、实型等数值类型,有加、减、乘、除等操作, 对逻辑类型,有逻辑与、逻辑或、逻辑非等操作。 对于用户自定义的复合数据类型,需要由程序员自己定义一些方法,对该类型的实例进行所需的操作。,抽象数据类型,对象是一种程序构造,有与之相关的数据(信息
2、),并可以执行某些动作。程序运行时,对象之间会进行交互,以实现程序设计需要完成的任务。 可以用对象来表示现实世界中的各种对象,比如汽车、房屋、雇员记录。 类是指一种或一类对象,同一个类的所有对象都具有相同类型的数据和行为。 类和对象是Java程序的基本组成要素。,类,类是现实世界某些对象的共同特征(属性和操作)的表示,对象是类的实例。 类的属性:就是类的静态属性的简称,指类内包含的各项数据,如变量或其他类的对象; 类的服务: 则被称为成员函数或方法。,类的基本定义,修饰符 class 类名 extends 父类 implements 接口名 类成员变量声明类方法声明 ,关于类头-class,c
3、lass关键字,在它的后面,应跟随新数据类型的名称。(注意不要把class写成Class)。 父类名跟在extends 关键字后面,用来说明当前类是哪个已经存在类的子类,存在继承关系。继承是类与类之间的一种非常重要的关系。,关于类头-类的修饰符,“public”(公共) 意味着后续的定义任何人均可使用。 “private”(私有)意味着除您自己、类型的创建者以及那个类型的内部函数成员,其他任何人都不能访问后续的定义信息。 “protected”(受保护的)与“private”相似,只是一个继承的类可访问受保护的成员,但不能访问私有成员。 “friendly”(友好的)若某样东西是“友好的”,意
4、味着它只能在这个包装的范围内使用(所以这一访问级别有时也叫作“包装访问”)。“,关于类头-接口名,接口名跟在implements关键字后面,用来说明当前类中实现了哪个接口定义的功能和方法。接口是Java语言用来实现多重继承的一种特殊机制,我们将在后面详细介绍它的使用方法。,关于类体,类体的定义要包括类的具体内容,包括类的属性与方法。,class ,关于类体-类的属性,Java中声明类属性为简单变量的语法如下:修饰符 变量类型 变量名 =变量初值;,变量类型和变量名是声明一个变量必不可少的部分;变量的类型是简单数据类型,如int、double等。,Java中声明方法的语法如下:修饰符 返回值类型
5、 方法名(参数列表) throws 例外名1,例外名2, 方法体:局部变量声明;语句序列; ,关于类体-类的方法,类中定义的方法通常起到两种作用:一是围绕着类的属性进行各种操作;二是与其他的类或对象进行数据交流、消息传递等操作。,关于类体-类的方法,Java语言中定义的方法有两类: 一类是需要程序书写专门的调用命令来调用的方法,称为程序调用方法,例如isPfime (); 另一类是运行过程中系统自动调用的方法,称为系统方法,例如我们前面程序中的action()、paint()、init()等。这两类方法的定义和使用原则有很大差异。,注意:系统调用方法的最大特点:不需要在程序里书写专门的调用方法
6、的命令,用户程序自定义类,Java程序员把注意力放在创建称为类的用户自定义类型(user-defined type)上,类也称为程序员定义的类型(programmer-defined type),每个类都含有数据和一组操作数据的方法,类中的数据部分称为实例变量。 用户定义类型(即类)的实例称为对象。,下面是一个简单化的Date类。,示例,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;
7、 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.month = 1;d.year +;return d;,daysInMonth() 返回每个月中不同的天数,抽象数据类型,在Java中把名为tomorrow的代码段叫做方法,也可以称为成员函数。 Java在数据和操作间建立
8、了较严格的联系,即把方法与数据封装在一个类中。,抽象数据类型,Data d = new Date ( 20, 11, 1998); /已初始化的date对象 d.tomorrow(); /tomorrow()方法作用于变量d 要访问Date类的域,可使用点操作符“.”:d.day /d所指的Date对象中的day域,定义方法,在Java中,方法定义的一般格式如下:() 是方法名,它必须使用合法的标识符。 说明方法返回值的类型。如果方法不返回任何值,它应该声明为void。Java对待返回值的要求很严格,方法返回值必须与所说明的类型相匹配。,定义方法,段可以含几个不同的修饰符。 是传送给方法的参数
9、表。表中各元素间以逗号分隔,每个元素由一个类型和一个标识符组成。 表示方法体,是要实际执行的代码段。,示例1,void setName (String name) this.name = name; String getAddress() return address; ,按值传送,Java只“按值”传送自变量,即方法调用不会改变自变量的值。 当对象实例作为自变量传送给方法时,自变量的值是对对象的引用,也就是说,传送给方法的是引用值。 在方法内,这个引用值是不会被改变的,但可以修改该引用指向的对象内容。当从方法中退出时,所修改的对象内容可以保留下来。,程序3,public class Pass
10、Test float ptValue;public static void main (String args ) String str;int val; PassTest pt = new PassTest ();val = 11; / 给整型量val赋值pt.changeInt (val); / 改变val的值,创建类的实例,/ val当前的值是什么呢?打印出来看看System.out.println (“Int value is: “ +val);/ 给字符串str赋值str = new String (“hello“);/ 改变str的值pt.changeStr (str);/ str
11、当前的值是什么呢?打印出来看看System.out.println (“Str value is: “ +str);/ 现在给ptValue赋值pt.ptValue = 101f;/ 现在通过对象引用改值pt.changeObjValue (pt);,/ 当前的值是什么呢?System.out.println ( “Current ptValue is: “ +pt.ptValue);/ 修改当前值的方法public void changeInt (int value) value = 55;public void changeStr (String value) value = new St
12、ring (“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.println(“The current date is (dd / mm / yy): “ +this.day +“ / “ +this.month +“ /
13、 “ +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:,public class DateUser public sta
14、tic 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 setDay(int tar
15、getDay) if (targetDay this.daysInMonth() System.err.println(“invalid day “ +targetDay);else this.day = targetDay; ,封装,如果对数据的访问是完全放开的,那么,程序会变得混乱且不易控制。 对于其他复杂的数据类型,类的使用者可能会疏忽对数据的一致性检查。,封装,封装是面向对象方法的一个重要原则。 它有两个基本涵义:一是指对象的全部属性数据和对数据的全部操作结合在一起,形成一个统一体,也就是对象;另一方面是指,尽可能地隐藏对象的内部细节,只保留有限的对外接口,对数据的操作都通过这些接口实
16、现。,重载方法名,如果需要在同一类中写多个方法,让它们对不同的变量进行同样的操作,就需要重载方法名。 在Java和其他几种面向对象的程序设计语言中,允许对多个方法使用同一个方法名,这就是方法名的重载。 当然,前提条件是能够区分实际调用的是哪个方法,才可用这种方式。,重载方法名,Java根据参数自变量的类型及参数的个数来区分这些方法。 例如:public void print(int i)public void print(float f)public void print(String s) 当调用print方法时,可根据自变量的类型选中相应的一个方法。,重载方法规则一,调用语句的自变量列表必
17、须足够判明要调用的是哪个方法。自变量的类型可能要进行正常的扩展提升(如浮点变为双精度),但在有些情况下这会引起混淆。,重载方法规则二,方法的返回类型可能不同。如果两个同名方法只有返回类型不同,而自变量列表完全相同则是不够的,因为在方法执行前不知道能得到什么类型的返回值,因此也就不能确定要调用的是哪个方法。重载方法的参数表必须不同,即参数个数或参数类型不同。,对象的构造和初始化,在说明了引用后,要调用new为新对象分配空间。 在调用new时,既可以带有变量,也可以不带变量。 系统根据所带参数的个数和类型,调用相应的构造方法。,对象的构造和初始化,调用构造方法时,步骤如下: (1)分配新对象的空间
18、,并进行默认的初始化。在Java中,这个过程是不可分的,从而可确保不会有没有初值的对象。 (2)执行显式的成员初始化。 (3)执行构造方法,构造方法是一个特殊的方法。,显式成员初始化,在成员说明中写有简单的赋值表达式,就可以在构造对象时进行显式的成员初始化。,示例,public class Initialized private int x = 5;private String name = “Fred“;private Date created = new Date();/ 成员的访问方法 . ,构造方法,显式初始化是为对象域设定初值的一种简单方法。 因为设定的初值不具有变化性,所以这种简单
19、的方法有其局限性。 系统定义了构造方法,同时允许程序员编写自己的构造方法完成不同的操作。,构造方法,构造方法是特殊的类方法,有着特殊的功能。它的名字与类名相同,没有返回值,在创建对象实例时由new运算符自动调用。 为了创建实例的方便,一个类可以有多个具有不同参数列表的构造方法,即构造方法可以重载。,示例,public class Xyz / 成员变量int x;public Xyz() x = 0;public Xyz(int i) x = i;,使用参数创建对象,创建对象,构造方法,因为构造方法的特殊性,它不允许程序员按通常调用方法的方式来调用。 构造方法不能说明为native,abstra
20、ct,synchronized或final,也不能从父类继承构造方法。,默认构造方法,每个类都至少有一个构造方法。如果程序员没有为类定义构造方法,系统会自动为该类生成一个默认的构造方法。 默认构造方法的参数列表及方法体均为空。,默认构造方法,如果程序员定义了一个或多个构造方法,则自动屏蔽掉默认构造方法。构造方法不能继承。 如果程序员定义了构造方法,那么,最好包含一个参数表为空的构造方法。,finalize方法,finalize方法属于Object类,它可被所有类使用。 如果对象实例不被任何变量引用时,Java会自动进行“垃圾回收”,收回该实例所占用的内存空间。,finalize方法,在对对象实
21、例进行垃圾收集之前,Java自动调用对象的finalize方法,它相当于C+中的析构方法,用来释放对象所占用的系统资源。,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 Man
22、ager private String name;private Date hireDate;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”Employe
23、e。,extends关键字,面向对象的语言提供了派生机制,它允许程序员用以前已定义的类来定义一个新类。 新类称作子类,原来的类称作父类或超类。两类中公共的内容放到父类中。 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 Employe
24、e private String department;private Employee subordinates; . ,extends关键字,派生机制改善了程序的可维护性,增加了可靠性。对父类Employee所做的修改延伸至子类Manager类中,而程序员不需做额外的工作。,单重继承,如果一个类有父类,则其父类只能有一个,Java只允许从一个类中扩展类。这条限制叫单重继承。 为了保留多重继承的功能,Java提出了接口的概念。 虽然一个子类可以从父类继承所有的方法和成员变量,但它不能继承构造方法。,单重继承,只有两种方法可让一个类得到一个构造方法,一种方法是自己编写一个构造方法,另一种方法是
25、,因为用户没有写构造方法,所以系统为类提供唯一一个默认的构造方法。,多态性,对象是多态的,即它们有“许多形式”。 在Java中,有一个很特殊的类,它是所有类的父类,这就是java.lang.Object类。 例: public class Employee extends Object,方法的参量和异类集合,1. 方法的参量 实际中,实例和变量并不总是属于同一类。 例 public TaxRate findTaxRate(Employee e) / 进行计算并返回e的税率 / 而在应用程序类中可以写下面的语句Manager m = new Manager();TaxRate t = findT
26、axRate(m);,这是合法的,因为Manager是一个Employee。,2. 异类集合,异类集合是由不同质内容组成的集合。 在面向对象的语言中,可以创建有公共祖先类的任何元素的集合。,instanceof运算符,由于类的多态性,类的变量既可以指向本类实例,又可以指向其子类的实例。 可以通过instanceof运算符来判明一个引用到底指向哪个实例 。,instanceof运算符,假定继承关系如下所示: public class Employee extends Object public class Manager extends Employee public class Contrac
27、tor extends Employee,instanceof运算符,则类之间的层次关系如下图所示:,示例,public void method(Employee e) if (e instanceof Manager) / 经理级人士else if (e instanceof Contractor) / 掌握公司机密的高层人士else / 普通雇员,转换对象,Java允许使用对象之父类类型的一个变量指示该对象。,下面的语句是合法的: Employee e = new Manager(); 使用变量e,可以只访问Employee对象的内容,而隐藏Manager对象中的特殊内容。,转换对象,对象
28、引用的赋值兼容原则允许把子类的实例赋给父类的引用,但不能把父类的实例赋给子类的引用。 如果用instanceof运算符已判明父类的引用指向的是子类实例,就可以转换该引用,恢复对象的全部功能。,示例,public void method(Employee e) if (e instanceof Manager) Manager m = (Manager)e;System.out.println(“This is the manager of “ +m.department);/ 其他操作 ,转换对象,一般地,要替换对象引用时需做下列检查: (1) 沿类层次向“上”转换总是合法的。实际上此种方式下
29、不需要转换运算符,只用简单的赋值语句就可完成。 (2) 对于向“下”替换,只能是父类到子类转换,其他类之间是不允许的。 (3) 编译器检查正确后,需在运算时检查引用类型,覆盖方法,使用类的继承关系,可以从已有的类产生一个新类,修改父类中已有的方法。 如果子类中定义方法所用的名字、返回类型和参数表和父类中方法使用的完全一样,称子类方法覆盖了父类中的方法,即子类中的成员方法将隐藏父类中的同名方法。,覆盖方法,利用方法隐藏,可以重定义父类中的方法。 覆盖的同名方法中,子类方法不能比父类方法的访问权限更严格。 在子类中,若要使用父类中被隐藏的方法,可以使用super关键字。,示例,class Poin
30、t 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 is the subclass!“);,示例,class Point1 void print() Sy
31、stem.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.print();,示例,public class Employee Strin
32、g 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 Employee(); M
33、anager 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.distan
34、ce() = “ +p.distance();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.414213562 p.distance() = 1.732050808,Java包,为了更好地组织类, Java提供了包机制。 包是类的容器,用于分隔类名空间。 Java中的
35、包一般均包含相关的类。 程序员可以使用package指明源文件中的类属于哪个具体的包。,Java包的概念,包语句的格式为: package pkg1.pkg2.pkg3.; 程序中如果有package语句,该语句一定是源文件中的第一条可执行语句,它的前面只能有注释或空行。 一个文件中最多只能有一条package语句。,Java包的概念,包的名字有层次关系,各层之间以点分隔。 包层次必须与Java开发系统的文件系统结构相同。 通常包名中全部用小写字母。,Java包的概念,当使用包说明时,程序中无需再引用(import)同一个包或该包的任何元素。import语句只用来将其他包中的类引入当前名字空间
36、中。而当前包总是处于当前名字空间中。 例:package java.awt.image; 则此文件必须存放在Windows的 javaawtimage目录下或unix的java/awt/image目录下。,import语句,在Java中,使用引入(import)语句告诉编译器要使用的类所在的位置。 包名也是类名的一部分。 例如,如果abc.FinanceDept包中含有Employee类,则该类可称作abc.FinanceDept.Employee。 引入语句的格式如下: import pkg1.pkg2.pkg3.(类名|*);,示例,假设有一个包a,在a中的一个文件内定义了两个类xx和yy
37、,其格式如下: package a; class xx. class yy. ,当在另外一个包b中的文件zz.java中使用a中的类时,语句形式如下:/ zz.java package b; import a.*; class zz extends xx yy y;. ,import语句,要引入所有类时,可以使用通配符“*”, 如:import java.lang.*; 引入整个包时,可以方便地访问包中的每一个类。 后果:会占用过多的内存空间,而且代码下载的时间将会延长。 建议:在了解了包的基本内容后,实际用到哪个类,就引入哪个类,尽量不造成资源的浪费。,目录层次关系及CLASSPATH环境变
38、量,包“存放”在包名构成的目录中。 在CLASSPATH中必须加入目录层次中的根abc。 如果程序员想访问其他地方放置的包,则必须显式设置CLASSPATH变量。,目录层次关系及CLASSPATH环境变量,如果在编译命令中使用-d选项,则Java编译器可以创建包目录,并把生成的类文件放到该目录中。 例: %javac -d /home/anton/mypackages/Employee.java,目录层次关系及CLASSPATH环境变量,CLASSPATH环境变量必须包含包路径:CLASSPATH=/home/anton/mypackages;由此,编译器能找到前例中Manager.java文件中的abc.FinanceDept.Employee类的所在位置。,