第三章Java面向对象编程.ppt
第三章:面向对象程序设计第三章:面向对象程序设计内容内容什么是面向对象编程?类和对象继承和多态抽象类和接口什么是面向对象程序设计?什么是面向对象程序设计?面向过程程序设计分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了。简而言之,面向过程程序设计是使用过程进行的程序设计。面向对象程序设计(OOP)(OOP)对要处理的问题进行自然分割,按照人的思维方式建立问题领域的模型,对客观实体进行结构模拟和功能模拟,设计出尽可能自然地的表现问题求解方法的问题。面向对象程序设计是使用对象进行程序设计。无论是面向过程还是面向对象,它们都是软件重用的一种思想而已对象是什么?类和对象类和对象对象是什么?对象是什么?对象代表现实世界中可以明确标识的一个实体。例如,一个学生,一张桌子,一个圆,一个按钮甚至一笔贷款都可以看作一个对象。对象有自己独有的特性、状态和行为。对象的状态是由具有当前值的数据域(属性)的集合构成的。对象的行为是由方法的集合定义的。调用对象的一个方法就是要求对象执行一项任务。例如,圆对象具有数据域radius,它是圆的特征属性。圆的一个行为就是使用getArea()方法计算它的面积。类和对象类和对象对象和类的关系对象和类的关系类就是定义同一类型对象的结构。类是一个模版或蓝本,用来定义对象的数据和行为。一个对象就是类的一个实例。我们可以从一个类中创建多个类的实例,创建实例的过程成为实例化Name:CircleDataField:radius is_Method:getArea();Circle1Radius is 10getArea()Circle2Radius is 25getArea()实例化类和对象类和对象类的创建类的创建在Java类中,用变量来定义数据域,方法来定义行为。此外类中还有一个特殊的方法成为构造方法,调用它可以实现类的实例化。因此,Java的类由数据、方法以及构造方法组成。Java中定义类的语法格式为:class 类名 数据;构造方法;方法;类和对象类和对象数据域的定义数据域的定义Java中数据域是用变量来定义的,因此我们可以用定义变量的方式来定义数据域,其格式如下:数据类型 数据名;(数据名的定义遵循Java标识符的规则)例如,我们需要对学生进行模拟建立学生的类,学生的属性是用数据域的集合来表示的,如下所示:public class Student private String name,deparment,sex;private int age;double length;类和对象类和对象方法的定义方法的定义类中定义的方法通常起到两种作用:1.围绕着类的属性进行各种操作;2.与其他的类或对象进行数据交流、消息传递等操作方法的定义分为:方法声明和方法体 返回类型 方法名()方法体;类和对象类和对象类的定义实例类的定义实例例如,定义圆对象的类如下:public class Circle double radius;public Circle()public double getArea()final double PI=3.14;return PI*radius*radius;数据域构造方法方法构造方法是什么?类和对象类和对象构造方法构造方法构造方法是一种特殊的方法,构造方法的特殊之处在于:一、构造方法必须与定义它的类的名字完全相同;二、构造方法没有返回类型,甚至连void都没有;三、构造方法的调用是在创建一个对象时使用new操作符进行的;四、其他规则遵行方法的定义规则;五、构造方法的作用是用来初始化对象;类可以不声明构造方法。这种情况下,类中隐含的声明了一个无参的构造方法,成为默认构造方法。类和对象类和对象构造方法的重载构造方法的重载引例:public class Circle double radius;public Circle()public Circle(double r)radius=r;public double getArea()final double PI=3.14f;return PI*radius*radius;两个构造方法但参数列表不同,这是什么?类和对象类和对象方法的重载方法的重载方法的重载方法的重载是指若干个方法具有相同的名字而具有不同的参数列表。public static int max(int x,int y)return x=y?x:y;public static double max(double x,double y)if(x=y)return x;else return y;类和对象类和对象重载方法的调用重载方法的调用在一类中同时出现两个同名的方法时,系统在调用方法时会根据方法中的参数列表不同自动加载的相应的方法。int max=max(3,4);double max=max(3.0,4.0);当然构造方法的重载也遵行这些规则。类和对象类和对象类的实例化类的实例化Java中创建对象的语法格式为:类名 对象名=new 类名();(调用相应的构造方法进行实例化)Circle circle1=new Circle();Cricle circle2=new Circle(3.25);类和对象类和对象访问对象的数据和方法访问对象的数据和方法对象已经创建后,我们就可以访问对象的数据和方法对象的数据和方法可以用点运算符(.)来访问。访问对象的数据:对象名.数据域名Circle circle1=new Circle(3.12);double radius=circle1.radius;调用对象的方法:对象名.方法名(参数)(方法的调用遵行调用规则)Cricle circle2=new Circle(3.12);double area=circle2.getArea();类和对象类和对象面向对象编程举例面向对象编程举例public class TestCricle public static void main(String args)Circle circle1=new Circle();System.out.println(“The area of circle of radius”+circle1.radius+“is”+circle1.getArea());Circle circle2=new Circle(6.0);System.out.println(“The area of circle of radius”+circle2.radius+“is”+circle2.getArea();class Cricle double radius;public Circle()radius=1;public Circle(double newRadius)radius=newRadius;public double getArea()final double PI=3.14f;return PI*radius*radius;类和对象类和对象类成员的修饰符类成员的修饰符在Java程序设计的过程中,我们需要类的成员的作用域以及类的成员归属问题做出限制,这样做将便于类的逻辑严密性。Java中的修饰符可分为两类:访问控制修饰符用来控制对数据域、方法和类的访问;类型说明符用来定义类的成员的特殊性质。访问控制修饰符有:public、protected、private、(default)类型说明符有:final、abstract、static类和对象类和对象访问控制符访问控制符publicpublic、privateprivate、defaultdefaultpublic修饰的类、数据和方法可以被任何类访问;private修饰的数据和方法只能被当前类中的成员使用;(defualt)修饰的类、数据和方法可以被包中任何类访问public class C1 public int x;int y;private int z;public void m1()void m2()private void m3()public class C2 void aMethod()C1 o=new C1();能访问o.x;能访问o.y;不能访问o.z;可调用o.m1();可调用o.m2();不可调用o.m3();public class C3 void aMethod()C1 o=new C1();能访问o.x;不能访问o.y;不能访问o.z;能调用o.m1();不能调用o.m2();不能调用o.m3();类和对象类和对象访问控制符(访问控制符(defaultdefault)如果类没有声明为public,那么仅能同一包中被访问。class C1 public class C2 可以访问C1的对象;public class C3 不能访问C1的对象;可以访问C2的对象;类和对象类和对象访问控制符应用举例访问控制符应用举例package p1;package p1;public class C1 class C2 public int x;public static void main(String args)int y;C1 o=new C1();private int z;System.out.println(o.x);public void m1()System.out.println(o.y);System.out.println(“m1被调用”);System.out.println(o.z);o.m1();void m2()o.m2();System.out.println(“m2被调用”);o.m3();private void m3()System.out.println(“m3被调用”);package p2;import p1.*;public class C3 public static void main(String args)C1 o=new C1();C2 o1=new C2();类和对象类和对象类型说明符类型说明符staticstaticCircle c1=new Cricle();Circle c2=new Circle(2.5)c1中的radius独立于c2中的radius,存储在不同的内存空间上。c1中radius的变化不会影响c2中的radius,反之亦然。radius属于类中一个特定的实例,称为实例变量radius=0Circle1radius=2.5Circle2类和对象类和对象静态成员静态成员如果想让一个类中的所有实例共享数据,就可以用静态变量。静态变量将变量值存储于类的公用内存中。如果某个对象修改了静态变量的值,同一个类的所有对象都会受到影响。如果想无需创建类的实例就调用类的方法,同样我们也可以将方法定义为静态方法。要声明一个静态变量或静态方法,只需在变量或方法说明中加上修饰符static类和对象类和对象静态变量、常量、方法静态变量、常量、方法静态变量numberofObjects、常量PI和静态方法getNumberofObjects可以声明如下:public static int numberofObjects;public final static double PI=3.14;public static int getNumberofObjects()return numberofObjects;静态成员的使用:类名.静态数据名或对象名.静态数据名 类名.静态方法名()或对象名.静态方法名()静态变量、常量既可以在静态方法中使用也可以在实例方法中使用,实例变量、常量只能在实例方法中使用。类和对象类和对象静态成员应用举例静态成员应用举例public class Circle public static int numberOfObjects;public final static double PI=3.14;double radius;public Circle()numberOfObjects+;public Circle(double newRadius)radius=newRadius;numberOfObjects+;public static int getNumberOfObjects()return numberOfObjects;public double getArea()return PI*radius*radius;类和对象类和对象静态成员应用举例静态成员应用举例public class TestCircle public static void main(String args)Circle c1=new Circle();System.out.println(“Before creating c2”);System.out.println(“c1 is:radius(”+c1.radius+“)and number of Circle objects(”+c1.numberOfObjects+“)”);System.out.println(“The number of Circle objects is”+Circle.numberOfObjects);Circle c2=new Circle(5.0);c1.radius=9;System.out.println(“After creating c2 and modifying c1s radius to 9”);System.out.println(“c1 is:radius(”+c1.radius+“)and number of Circle objects(”+c1.numberOfObjects+“)”);System.out.println(“c2 is:radius(”+c2.radius+“)and number of Circle objects(”+c2.numberOfObjects+“)”);System.out.println(“The number of Circle Objects is”+Circle.numberOfObjects);类和对象类和对象参数传递参数传递引例:public class Circle public double radius;public Circle(double newRadius)radius=newRadius;public double getArea()final double PI=3.14;return PI*radius*radius;类和对象类和对象参数传递参数传递引例:public class example public static void main(String args)double radius=2.5;Circle c=new Circle(radius);double area1=getArea(radius);System.out.println(“The area is”+area1);System.out.println(“After invoke,the radius is”+radius);double area2=getArea(c);System.out.println(“The area is”+area2);System.out.println(“After invoke,the radius is”+c.radius);public double getArea(double radius)final double PI=3.14F;double area=PI*radius*radius;radius=radius+1.0f;return area;public double getArea(Circle circle)double area=circle.getArea();circle.radius=circle.radius+1.5f;return area;思考一下,两次求面积之后圆的半径发生的变化?基本数据类型和引用数据类型基本数据类型和引用数据类型每个变量代表一个存储值的内存单元。对于基本数据类型变量而言,对应内存所存储的值是基本数据类型,它的值为对应内存中的所存储的值。对于引用数据类型变量而言,它的值是一个引用,是对象的存储地址。基本数据类型 对象类型 int i=1;Circle c i c 1引用c:Circleradius=1基本数据类型和引用数据类型的赋值基本数据类型和引用数据类型的赋值int i=1,j=2;Circle c1=new Circle(2.5);i=j;Circle c2=new Circle(4.0);i j c1=c2;c1 c2 i j1222c1:Circleradius=2.5c1:Circleradius=4.0类和对象类和对象参数传递参数传递Java中参数的传递有两种方式:按数值进行传递:传递的方向是单向的,只能有实参传给形参(将实参值的一个副本传给了形参),而不能有形参传给实参,因此,方法中形参发生的任何变化将不会影响到实参的值,如上例中double area1=getArea(radius)中采用的方式。按引用值进行传递:将引用数据类型的引用值传入方法内部,形参在方法中的变化将会影响到实参中的内容。如上例中double area2=getArea(c)中采用的方式。类和对象类和对象对象作为方法的参数对象作为方法的参数对象作为方法的参数,实参与形参之间的参数传递是通过引用值的传递的来完成的。以引例中的double area2=getArea(c)为例来详细说明其参数传递过程以及形参和实参之间的相互作用。radius=2.5cint radius=2.5;int radius=2.5;Circle c=new Circle(radius);Circle c=new Circle(radius);circle=c;circlecircle.radius=circle.radius+1.circle.radius=circle.radius+1.5f5fdouble area2=getAreadouble area2=getArea(c c)radius=2.5+1.5f=4.0f类和对象类和对象应用举例应用举例1 1class dataEnity int i,j,k;public dataEnity()public dataEnity(int new_i,int new_j,int new_k)i=new_i;j=new_j;k=new_k;类和对象类和对象应用举例应用举例2 2public class TestObject public static void main(String args)dataEnity db=new dataEnity(23,10,45);System.out.println(“Before changed:”);System.out.println(“db.i=”+db.i+”db.j=”+db.j+”db.k=”+db.k);swap(db);System.out.println(“After changed:”);System.out.println(“db.i=”+db.i+”db.j=”+db.j+”db.k=”+db.k);public static void swap(dbEnity db)int temp;if(db.idb.j)temp=db.i;db.i=db.j;db.j=temp;if(db.idb.k)temp=db.i;db.i=db.k;db.k=temp;if(db,=.jdb.k)temp=db.j;db.j=db.k;db.k=temp;System.out.println(“db.i=”+db.i+”db.j=”+db.j+”db.k=”+db,k);类和对象类和对象thisthis关键字的使用关键字的使用变量定义的位置决定了变量的作用域,按照变量的作用域,变量可以分为类变量和局部变量;请看下面的例子:public class example private int data;public example(int data)将局部变量data的值赋给类变量data;当类变量和局部变量同名时,我们却要在定义局部变量的方法中使用类变量,怎么办?类和对象类和对象thisthis关键字的使用关键字的使用当在一个方法中局部变量和类变量重名时,类变量将会被局部变量所覆盖。如果要在该方法中使用类变量,this关键字将会是你的选择。this指向当前对象的一个引用变量。即this表示的是当前对象本身,利用它可以调用当前对象的方法或者数据。public example(int data)this.data=data;类和对象类和对象类的封装类的封装引例:class Circle double radius;public circle(double radius)this.radius=radius;public double getArea()final double PI=3.14;return PI*radius*radius;public class TestCirclepublic class TestCircle public static void main(String args)public static void main(String args)Circle c=new Circle(2.5);Circle c=new Circle(2.5);System.out.println(c.radius);System.out.println(c.radius);c.raidus=c.radius+1.5f;c.raidus=c.radius+1.5f;System.out.println(c.radius);System.out.println(c.radius);c.radius=-1.0f;c.radius=-1.0f;System.out.println(c.radius);System.out.println(c.radius);类和对象类和对象引例分析引例分析上例中对象c的半径可以通过c.radius=?来直接进行修改,这样做就导致以下问题:第一,数据可能被篡改,我们知道对于一个指定的圆,它的半径应该是事先测量好不可逆。第二,它使类难于维护并且不易调试。上例通过c.radius=-1.0f将圆的半径修改一个负值。因此,为了避免在其他类中直接修改对象的属性或数据,应该使用private 修饰为私有域,这个过程称为数据域封装,它是类的封装的一种简单形式。类和对象类和对象数据域封装数据域封装如果我们将类的数据域定义为private的,有时使用对象的类还是要经常存取、修改数据域,因此,为了能够访问私有数据域,可以编写一个get方法返回数据域的值,为了修改它,可以编写一个set方法设置新值,这两个方法分别称为访问器和修改器。get方法的签名如下:public 返回类型 get属性名()return 属性名;public double getRadius()return radius;类和对象类和对象数据域封装数据域封装set方法的签名如下:public void set属性名(参数列表)赋值语句;public void setRadius(double radius)this.radius=radius;类和对象类和对象数据域封装应用举例数据域封装应用举例public class Circle private double radius;public double getRadius()return radius;public void setRadius(double radius)this.radius=radius;public Circle(double radius)this.radius=radius;public double getArea()final double PI=3.14f;return PI*radius*radius;类和对象类和对象数据域封装应用举例数据域封装应用举例public class TestCircle()public static void main(String args)Circle c=new Circle(5.0);System.out.println(“The radius of c is”+c.getRadius();c.setRadius(4.0);System.out.println(“The radius after changed is”+c.getRadius();类和对象类和对象类的封装类的封装封装是指面向对象程序设计的基本特点。所谓封装性,是把具有功能和数据的组件作为一个“黑盒子”,该组件提供给用户某些调用接口,组件的使用者不必清楚组件内部的工作原理,只需调用暴露在组件外的接口即可。面向对象强调的是对数据的抽象,因此更多的情况是隐藏成员变量,而暴露出成员的方法作为访问对象状态的接口。数据域封装是类的封装的基本方式。类和对象类和对象包包什么是包?包是类的组织方式,是Java提供的一种区别类命名空间的机制。包对应一个文件夹,包中还可以再有包,称为包等级。为什么要使用包?使用对象进行程序设计最重要的原因是为了提高程序中代码的重用率,因此公共资源可以重用是面向对象程序设计的一个重要特点。在Java中,当应用软件比较多时,如果将所有文件放在一个文件夹中,管理起来就比较麻烦,以后的软件资源重用就不方便,通过包可以方便的解决此类问题。类和对象类和对象包的声明包的声明Java中声明包的语法格式如下:package pkg1.pkg2包的声明语句必须放在Java文件的首行,“.”表示目录分隔符,它表示pgk3目录在pgk2下,pgk2目录在pgk1下,一次类推,这些目录形成了一个树状结构。例如package cn.edu.zjut语句声明了一个包,这将java文件的目录之下生成如下图所示的树状结构.类和对象类和对象包的声明包的声明在一个程序的声明一个包后,程序编译好的.class文件会自动存放在该所对应的文件夹下。若要在编写Java程序时要声明包,建议使用诸如Jcreator之类的编程软件来进行编程。类和对象类和对象包的使用包的使用当一个类中要使用在另一个包下定义的类的时候,通过import语句来显式说明可以在一个类中使用在另一个包中的类。利用import语句导入其他包中的类的语法格式如下:import pkg1.pkg2.类名(*);(“*”表示引入包中的所有类)为了使用用户自定义的包中的类,用户必须配置ClassPath路径类和对象类和对象包的应用举例包的应用举例package cn.edu.zjut.circle;public class Circle private double radius;public double getRadius()return radius;public void setRadius(double radius)this.radius=radius;public Circle(double radius)this.radius=radius;public double getArea()return Math.PI*radius*radius;类和对象类和对象包应用举例包应用举例package cn.edu.zjut.main;import cn.edu.zjut.circle;public class TestPackage public static void main(Stringargs)Circle c1=new Circle(4.0);Circle c2=new Circle(2.5);CompareArea(c1,c2);public void CompareArea(Circel c1,Circle c2)double area1=c1.getArea();double area2=c2.getArea();if(area1=area2)System.out.println(“The bigger one is c1(“+c1.getRadius()+”)”);else System.out.println(“The bigger one is c2(”+c2.getRadius()+”)”);重构重构javajava程序的基本单元程序的基本单元package pgk1.pgk2;/声明一个包,以将该类包含在这个包中 import pgk1.pgk2.className(*)/导入一个包,以使用包中的类 class 类名 数据域;方法;继承和多态继承和多态继承的概念继承的概念什么是继承?在面向对象程序设计中,可以从已有类中派生出新类,这就是继承。例如,如果已经存在了一个人的类Person,我们就可根据这个Person类派生出一个新类一个公司的职员类。为什么要继承?如果我们希望一个类拥有已有类的属性和行为,同时还需要具有自己独特属性和行为,就可以使用继承。Java中所有类都来自于一个已存在的类,或者显示声明的,或是隐式的(java.lang.object)继承和多态继承和多态父类和子类父类和子类在java中,从另一个类C2中派生出的类C1称为子类或者次类、扩展类、派生类。类C2称为父类或基类、超类。Java中对类的继承是单向的,也就是说一个类有且只能有一个父类。继承完成以后,子类可以从它的父类中继承可访问的数据域和方法,同时也可以添加新的数据域和方法。那么如何创建一个子类或者派生类呢?继承和多态继承和多态子类的语法格式子类的语法格式Java中定义一个子类的语法格式如下:class 子类名 extends 父类 数据域;方法;继承和多态继承和多态继承应用举例继承应用举例例如,我们考虑几何对象。假设要设计模拟几何对象的类,如圆和矩形。几何对象有很多共有的属性和行为,可以用什么颜色画出来、填充或不填充。这样的话,我们需要编写一个通用的GeometricObject的类可以用来模拟所有几何对象。这个类包括属性color和filled,以及相应的get和set方法。假设该类中还包括dateCreated属性以及getDateCreated()和toString()方法。(toString()返回代表该对象的字符串)。圆是一种通用的几何对象,他和其他几何对象共享通用的属性和方法,因此,通过GeometricObject类来定义Circle就很具有意义,当然矩形类Rectangle也可以。继承和多态继承和多态几何对象的几何对象的UMLUML图图GeometricObject-color:String-filled:boolean-dateCreated:java.util.Date+GeometricObject()+getColor():String+setColor(color:String)+isFilled():boolean+setFilled(filled:boolean)+getDateCreated():java.util.Date+toString():String Circle-radius:double+Circle()+Circle(radius:double)+getRadius():double+setRadius(radius:double)+getArea():double+getPerimeter():doubleRectangle-width:double -height:String+Rectangle()+Rectangle(width:double,height:double)+getWidth():double +getHeight():double+setWidth(width:doulbe)+setHeight(height:double)+getArea():doulbe+getPerimeter():double继承和多态继承和多态继承的实现继承的实现父类GeometricObject的代码如下:子类Circle的代码如下:子类Rectangle的代码如下:测试程序TestCircleRectangle:从上述实例我们可以知道,子类不仅继承了父类中可访问的数据和方法,还具有自己独特的数据和方法。子类访问继承于父类的的数据和方法的语法格式遵行对象访问数据和方法的规则继承和多态继承和多态supersuper关键字关键字子类从父类中继承了可访问的数据和方法,那么它能够继承父类的构造方法吗?我们能从子类中调用父类的构造方法吗?super关键字this关键字指向对象本身,关键字super指向使用它的类的父类。super可以用于一下两种途径:(1)调用父类的构造函数;(2)调用父类的方法调用父类的构造方法的语法格式如下:super();或super();super()调用父类的无参构造函数,super()调用与参数匹配的父类构造方法。继承和多态继承和多态调用父类的构造方法调用父类的构造方法public class Person private String name;private String sex;public Person()public Person(String name)this.name=name;public Person(String name,String sex)this.name=name;this.sex=sex;继承和多态继承和多态调用父类的构造方法调用父类的构造方法public class employee extends Person public employee()super();public employee(String name)super(name);public employee(String name,String sex)super(name,sex);注:语句super()或super()必须出现在子类构造方法的第一行,而且这 是调用父类构造方法的唯一方法。当子类的构造方法没有显式的调用父类的构造方法时,编译器会将super()当做构造方法的第一条语句。public employee()等价于:public employee()super();继承和多态继承和多态利用利用supersuper调用父类的方法调用父类的方法super 调用父类的方法的语法格式如下:super.方法名();例如,在子类Circle中可以通过下述语句调用父类GeometricObject中的getDateCreated()方法 super.getDateCreated();当然,我们明白其实在Circle中,我若想调用getDateCreated()方法可以直接通过getDateCreated()语句即可调用没有必要使用super关键字,但是有些情况下,若想调用父类的方法必须使用super关键字。继承和多态继承和多态方法的覆盖与方法的覆盖与supersuper子类从父类中继承方法。有时,子类必须修改父类中定义的方法,这叫做方法的覆盖。例如上例,GeometricObject类返回表示几何对象的字符串,这个方法就可以覆盖,返回表示圆的字符串。public class Circle extends GeometricObject /原有属性和方法 /*重载父类GeometricObject中定义的toString()方法*/public void toString()System.out.println(super.toString()+”nradius is”+radius);继承和多态继承和多态重载和重载和supersuper因此,当父类中的方法在子类中被重载之后;若在子类中还想调用父类中的原方法,只有通过super关键字才能进行。子类并不能重载父类的任意方法