《Java程序设计及应用》.ppt
第第6讲:面向对象(讲:面向对象(1)内容提要内容提要1.人与计算机的关系人与计算机的关系2.物理世界与面向对象物理世界与面向对象 3.类与对象类与对象 4.面向对象基本特征面向对象基本特征1.封装1.访问修饰符2.继承3.多态1.重载2.覆盖教学要求教学要求v物理世界与面向对象的思想、方法物理世界与面向对象的思想、方法 v计算机面向对象的思想、方法计算机面向对象的思想、方法 v如何定义一个类以及创建其实例如何定义一个类以及创建其实例v面向对象的三个基本特征面向对象的三个基本特征人与计算机的关系人与计算机的关系 v人处于主体地位,计算机只能处于从属地位人处于主体地位,计算机只能处于从属地位。v计算机必须能够模拟这个物理世界计算机必须能够模拟这个物理世界。v计算机是个小世界,而物理世界是个大世界,小计算机是个小世界,而物理世界是个大世界,小世界来源于大世界世界来源于大世界 物理世界的认知物理世界的认知 v(1)世界由万物构成。)世界由万物构成。v(2)事物是运动的、发展的、变化的。)事物是运动的、发展的、变化的。v(3)事物之间的关系是复杂的、多变的。)事物之间的关系是复杂的、多变的。事物的基本特征事物的基本特征 v(1)封装。)封装。保护功能相对独立性v(2)继承)继承 加快事物发展的速度提高事物发展的质量v(3)多态。)多态。透过现象抓本质,以不变应万变。事物间的关系事物间的关系 v泛化关系(泛化关系(Generalization)v聚合关系(聚合关系(Aggregation)v组合关系(组合关系(Composition)v依赖关系(依赖关系(Dependency)v关联(关联(Association)。)。类与对象类与对象 v世界由万物构成,经由前面的学习,我们知道研究物理世世界由万物构成,经由前面的学习,我们知道研究物理世界要用分类的方法。在面向对象程序设计中用类界要用分类的方法。在面向对象程序设计中用类(class)来模拟一类事物。)来模拟一类事物。v类的定义需用关键字类的定义需用关键字 class,定义一个简单类的语法如下:,定义一个简单类的语法如下:vclass 类名类名/该行称为类头,大括号之间的部分称为该行称为类头,大括号之间的部分称为类体类体 零或多个属性零或多个属性;零或多个方法零或多个方法;v其中属性的定义格式有两种,如下:其中属性的定义格式有两种,如下:v(1)类型)类型 属性名属性名=属性值属性值;v(2)类型)类型 属性名属性名1=属性值属性值1,属性名属性名2=属性值属性值2,.;类定义举例类定义举例v1 class Student 2 String sno;/学号学号 3 String name,major;/姓名姓名,专业专业 4 int age;/年龄年龄 5 6 void showInfo()7 (学号学号:+sno+t姓名姓名:+name+8 t年龄年龄:+age+t专业专业:+major);9 10 11 Student()/第一种构造方法第一种构造方法 12 13 14 /*第二种构造方法第二种构造方法*/15 Student(String sno1,String name1,String major1,int age1)16 sno=sno1;17 name=name1;18 major=major1;19 age=age1;20 21 22 实例对象实例对象v实例对象可以使用类的构造方法和实例对象可以使用类的构造方法和new关键字构关键字构造出来。语法为:造出来。语法为:类名 对象引用=new 构造方法;v例如:例如:Student t=new Student();类的成员类的成员v1成员属性的定义成员属性也称为成员变量,定义一个成员属性,格式为:修饰符 类型 成员属性名=成员属性值;例如:int a=10;int b;String s1;String s2=new String(abc);其中修饰符暂不讲,详见3.8节。v2成员方法的定义语法为:修饰符 返回类型 方法名(形式参数列表)throws 异常类型列表/方法头 执行语句块;/方法体 成员变量的初始化成员变量的初始化 成员变量类型默认值成员变量类型默认值 boolean false char(即空字(即空字符)符)byte,short,int 0 long 0L float 0.0F double 0.0D 引用类型引用类型 null 构造方法构造方法 v当使用当使用new关键字创建一个类实例对象时,系统关键字创建一个类实例对象时,系统(JVM)会自动调用该类的构造方法来完成类实)会自动调用该类的构造方法来完成类实例对象的构建,从而构造方法对类定义来说是必例对象的构建,从而构造方法对类定义来说是必须的。那么我们在类中如何声明一个构造方法呢须的。那么我们在类中如何声明一个构造方法呢?如下:?如下:v访问修饰符访问修饰符 类名类名(参数列表参数列表)/.构造方法的几点说明构造方法的几点说明v(1)构造方法的访问修饰符可以是)构造方法的访问修饰符可以是public,protected或者缺省(即不用访问修饰符),但不允许或者缺省(即不用访问修饰符),但不允许private。v(2)构造方法的名称和类名相同,但没有返回类型。)构造方法的名称和类名相同,但没有返回类型。v(3)若没有定义任何构造方法,则在编译阶段编译器会)若没有定义任何构造方法,则在编译阶段编译器会在编译后的字节码文件中插入一个默认的构造方法,默认在编译后的字节码文件中插入一个默认的构造方法,默认的构造方法是:无参数列表,访问修饰符和类的访问修饰的构造方法是:无参数列表,访问修饰符和类的访问修饰符相同,方法体内为空。符相同,方法体内为空。v(4)构造方法本身不能递归调用。)构造方法本身不能递归调用。v(5)构造方法体的最后一行语句可以是空的)构造方法体的最后一行语句可以是空的return语句,语句,即即“return;”,也可以不用,也可以不用return语句。语句。v(6)可在一个类中定义多个构造方法,其区别在于参数)可在一个类中定义多个构造方法,其区别在于参数列表不同,这是构造方法的重载。关于重载,详见节。列表不同,这是构造方法的重载。关于重载,详见节。封装的封装的Java表达与访问修饰符表达与访问修饰符 v封装有两个作用:保护作用和增强对象的独立性。封装有两个作用:保护作用和增强对象的独立性。保护作用是通过设置访问修饰符来实现的。保护作用是通过设置访问修饰符来实现的。v访问修饰符有访问修饰符有4个:个:public、protected、默认、默认访问修饰符、访问修饰符、private。其中默认访问修饰符就。其中默认访问修饰符就是没有修饰符,即不用是没有修饰符,即不用public、protected、private中的任何一个。访问修饰符用于对类、中的任何一个。访问修饰符用于对类、成员属性和成员方法设置访问权限,对它们实施成员属性和成员方法设置访问权限,对它们实施保护作用。保护作用。访问修饰符访问修饰符v(1)public可用于修饰类、成员变量和方法。可用于修饰类、成员变量和方法。表明该成员变量和方法是共有的,能在任何情况表明该成员变量和方法是共有的,能在任何情况下被访问。下被访问。Java应用程序中的应用程序中的main()方法必须方法必须用用public来修饰(否则能通过编译,但不能运行)来修饰(否则能通过编译,但不能运行),就是为了使,就是为了使JVM能够访问它。能够访问它。v在一个源代码文件中最多只能定义一个在一个源代码文件中最多只能定义一个public类,类,且该类名必须和源代码文件同名。且该类名必须和源代码文件同名。v(2)protected只能用于修饰成员属性或成员只能用于修饰成员属性或成员方法,不能修饰类。用方法,不能修饰类。用protected修饰的成员可修饰的成员可以被同包(以被同包(package)下其他类方法访问,也可)下其他类方法访问,也可以被不同包下的子类方法访问。以被不同包下的子类方法访问。v(3)默认访问修饰符修饰的成员只能被同包下的)默认访问修饰符修饰的成员只能被同包下的类方法访问。类方法访问。v(4)private修饰的成员只能被同类中的方法来修饰的成员只能被同类中的方法来访问。访问。v这这4种访问修饰符的访问范围由大到小,或安全保种访问修饰符的访问范围由大到小,或安全保护程度由低到高依次是:护程度由低到高依次是:public、protected、默认访问修饰符、默认访问修饰符、private。举例举例v1 class T 2 private String s=abc;3 public String getS()/称作访问方法称作访问方法 4 return s;5 6 7 8 class Test 9 public void func()10 T t=new T();11 String s1=t.s;/非法非法 12 String s2=t.getS();/合法合法 13 14 继承继承v继承的作用:一是提高了软件的开发速度,二是继承的作用:一是提高了软件的开发速度,二是提高了开发软件的质量。提高了开发软件的质量。v继承有广义和狭义之分。继承有广义和狭义之分。广义的继承有些拿来主义的味道,因此在Java中分为横向手法和纵向手法。横向手法是指采用import语句来继承要使用的类或Java接口;纵向手法是指采用extends关键字来实现的手法。狭义的继承就是只指纵向手法。无论是横向手法还是纵向手法都不违背继承的两个作用。在面向对象编程中继承概念通常是指狭义的。举例举例v1 class Student 2 public void func()3 System.out.println(Student);4 5 6 7 class Freshman extends Student 8 public static void main(String args)9 Freshman b=new Freshman();10 11 /*能够调用能够调用 Freshman 对象的对象的 func 方法方法,12 *说明说明 func 来自来自 Student.13 */14 b.func();15 16 vJava不支持多重继承,单继承使不支持多重继承,单继承使Java的继承关系很简单,一个类只的继承关系很简单,一个类只能有一个父类,易于管理程序,同时一个类可以实现多个接口(详见能有一个父类,易于管理程序,同时一个类可以实现多个接口(详见3.6节),从而克服单继承的缺点。节),从而克服单继承的缺点。v继承描述的是一种继承描述的是一种is a关系,例如上例关系,例如上例Freshman is a Student,是一种特殊与一般的关系。,是一种特殊与一般的关系。v继承是在两个不同的类之间发生的一种关系,被继承的内容是建立在继承是在两个不同的类之间发生的一种关系,被继承的内容是建立在访问权限(受访问修饰符控制)可访问的基础上的,有以下结论。访问权限(受访问修饰符控制)可访问的基础上的,有以下结论。v(1)子类的访问修饰符不小于父类的访问修饰符()子类的访问修饰符不小于父类的访问修饰符(private默认默认protectedpublic)。)。v(2)private修饰的成员不可以被继承。修饰的成员不可以被继承。v(3)默认访问修饰符修饰的成员只能被同包下的其他类继承。)默认访问修饰符修饰的成员只能被同包下的其他类继承。v(4)构造方法不能被继承。父类)构造方法不能被继承。父类+属性属性1v#属性属性2v-属性属性3+方法方法()子类图子类图3.2 类的继承关系类的继承关系v(5)不管父类是否是)不管父类是否是abstract的,子类可以声明为的,子类可以声明为abstract的,的,同样,父类中的方法不管是否是同样,父类中的方法不管是否是abstract的,在子类中都可以把该的,在子类中都可以把该方法声明为方法声明为abstract的。的。继承的继承的UML表示表示父类+属性1#属性2-属性3+方法()子类图3.2 类的继承关系this与与super关键字关键字 vthis代表类实例对象自身,代表类实例对象自身,super代表父类实例代表父类实例对象对象。v在一个类中可以定义多个构造方法,若在一个构在一个类中可以定义多个构造方法,若在一个构造方法中调用另一个构造方法时,必须使用造方法中调用另一个构造方法时,必须使用this。vsuper不可以连续使用。不可以连续使用。多态的多态的Java表达表达vava表达多态的方式有两种:表达多态的方式有两种:一是重载(overload)二是覆盖(override)。重载重载v重载是指在同一个类中定义多个同名方法,要求他们的参重载是指在同一个类中定义多个同名方法,要求他们的参数列表不同。区分重载方法只数列表不同。区分重载方法只 能通过参数列表,例如:能通过参数列表,例如:v1 class T 2 public void func()3 System.out.println(func();4 func(10);/输出结果为输出结果为 a=10 5 6 public void func(int a)7 System.out.println(a=+a);8 9 protected int func(int a,int b).10 String func(String s).11 重载说明重载说明v重载方法对修饰符列表、返回类型、抛出异常类型(详见重载方法对修饰符列表、返回类型、抛出异常类型(详见第第5章)是否相同均不作要求,区别仅仅在于参数列表。章)是否相同均不作要求,区别仅仅在于参数列表。v重载方法是程序的一种静态结构,即重载方法之间的关系重载方法是程序的一种静态结构,即重载方法之间的关系在编译器编译后就确定了,不会随程序代码的执行来动态在编译器编译后就确定了,不会随程序代码的执行来动态确定,这一点和覆盖不同,覆盖是程序的一种动态结构。确定,这一点和覆盖不同,覆盖是程序的一种动态结构。正是由于重载是一种静态结构,所以完全可以把重载方法正是由于重载是一种静态结构,所以完全可以把重载方法看作是各自不同的方法,这一点与不同名的方法之间的关看作是各自不同的方法,这一点与不同名的方法之间的关系没有什么区别。系没有什么区别。v在一个重载方法内可以直接调用另外一个重载方法,但在在一个重载方法内可以直接调用另外一个重载方法,但在一个重载的构造方法内却不能直接调用另一个重载的构造一个重载的构造方法内却不能直接调用另一个重载的构造方法,必须使用方法,必须使用this。覆盖覆盖 v覆盖是指在具有继承关系的两个不同类中定义同名方法,覆盖是指在具有继承关系的两个不同类中定义同名方法,是建立在继承的基础上的,要求如下:是建立在继承的基础上的,要求如下:v(1)private方法不能被覆盖,因为方法不能被覆盖,因为private方法不允方法不允许被继承。许被继承。v(2)方法名、返回类型、参数列表必须相同。)方法名、返回类型、参数列表必须相同。v(3)子类方法的访问修饰符)子类方法的访问修饰符父类方法的访问修饰符。父类方法的访问修饰符。v(4)子类中的覆盖方法的修饰符不能是)子类中的覆盖方法的修饰符不能是final、static,因为因为final修饰的标识符是不可改变的,而覆盖就是对父修饰的标识符是不可改变的,而覆盖就是对父类方法的一种修改,若父类方法不需要修改,只采用继承类方法的一种修改,若父类方法不需要修改,只采用继承就好了。就好了。static是一种静态行为,而覆盖则是一种动态行是一种静态行为,而覆盖则是一种动态行为。为。v(5)子类中的覆盖方法声明的抛出异常不能是父类被覆)子类中的覆盖方法声明的抛出异常不能是父类被覆盖方法声明的抛出异常的祖先类,只能是其子类或同类。盖方法声明的抛出异常的祖先类,只能是其子类或同类。子类中的覆盖方法也可以不声明抛出异常,尽管父类中的子类中的覆盖方法也可以不声明抛出异常,尽管父类中的被覆盖方法声明抛出了异常。详见第被覆盖方法声明抛出了异常。详见第5章。章。成员变量的覆盖成员变量的覆盖v方法可以被覆盖,成员变量也可以被覆盖。方法可以被覆盖,成员变量也可以被覆盖。v举例举例1 class T1 2 public String s=T1;3 public String getS()4 return s;5 6 7 class T2 extends T1 8 public String s=T2;9 public String getS()10 return s;11 12 13 class Test 14 public static void main(String args)15 T1 t1=new T1();16 T2 t2=new T2();17 18 System.out.println(t1.s);/输出 T1 19 System.out.println(t1.getS();/输出 T1 20 System.out.println(t2.s);/输出 T2 21 System.out.println(t2.getS();/输出 T2 22 23 t1=t2;24 System.out.println(t1.s);/输出 T1,而不是 T2 25 System.out.println(t1.getS();/输出 T2,而不是 T1 26 27 程序分析程序分析v从上面程序从上面程序24、25两行代码的输出结果,可以得出如下两行代码的输出结果,可以得出如下结论:结论:v(1)成员变量可以被覆盖。)成员变量可以被覆盖。v(2)若直接访问发生覆盖的成员变量,则只能访问引用)若直接访问发生覆盖的成员变量,则只能访问引用类型的成员变量,上例中第类型的成员变量,上例中第24行,虽然行,虽然t1指向的对象是指向的对象是T2类型的,但引用类型的,但引用t1的类型是的类型是T1,故输出结果是,故输出结果是T1。v(3)若通过发生覆盖的方法来访问发生覆盖的成员变量,)若通过发生覆盖的方法来访问发生覆盖的成员变量,则访问的成员变量和方法属于同一个对象,例如第则访问的成员变量和方法属于同一个对象,例如第25行,行,t1指向的对象是指向的对象是T2类型的,方法类型的,方法getS()是属于是属于T2实例实例对象的,故访问的变量是对象的,故访问的变量是T2实例对象的。实例对象的。v所以,若上例中没有第所以,若上例中没有第8行代码,则成员变量行代码,则成员变量s会被继承,会被继承,从而第从而第25行代码的输出是行代码的输出是T1。若没有第。若没有第911行代码,行代码,会发生方法的继承,但方法本身还是类会发生方法的继承,但方法本身还是类T1的,不是的,不是T2的,的,故第故第25行代码的输出是行代码的输出是T1。小结小结1.物理世界与面向对象物理世界与面向对象 2.类与对象类与对象 3.面向对象基本特征面向对象基本特征1.封装1.访问修饰符2.继承3.多态1.重载2.覆盖作业作业v习题习题 3:1,2,3