




免费预览已结束,剩余38页可下载查看
下载本文档
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
Java程序设计,重庆交大,21:19,上一章内容回顾,5.面向对象:构造方法,封装与隐藏构造器理解构造器构造器的重载封装理解封装访问控制符包(package)包及其作用package和import语句Java的常用包,21:19,6.面向对象:继承和多态,6.1类的继承6.1.1继承的特点6.1.2重写父类的方法6.1.3父类实例的super引用6.1.4调用父类的构造器6.2多态6.2.1多态性6.2.2引用变量的强制类型转换6.2.3instanceof运算符6.3继承和组合6.4课后作业,21:19,6.1类的继承6.1.1继承的特点,继承是面向对象三大特征之一,也是实现软件复用的重要手段。Java的继承通过关键字extends来实现,实现继承的类称为子类,被继承的类称为基类、超类、父类。父类与子类的关系,是一种一般和特殊的关系。例如水果和苹果的关系,苹果继承了水果,苹果是水果的子类,则苹果是一种特殊的水果。因为子类是一种特殊的父类,因此父类包含的范围总比子类包含的范围要大,因此父类是大类,子类是小类。Java的继承是单继承,每个类最多只有一个直接父类。,21:19,6.1类的继承6.1.1继承的特点,Java里子类继承父类的语法格式如下:修饰符classsubclassextendssuperclass/类定义部分“extends”的含义是子类扩展了父类,将可以获得父类的全部属性和方法,但子类不能获得父类构造方法。以下程序示范了子类继承父类的特点。,21:19,6.1类的继承6.1.1继承的特点,程序清单:chapter06test1Fruit.java、Apple.java,packagechapter06.test1;publicclassFruitpublicdoubleweight;publicvoidinfo()System.out.println(我是一个水果!重+weight+g!);,packagechapter06.test1;publicclassAppleextendsFruitpublicstaticvoidmain(Stringargs)/创建Apple的对象Applea=newApple();/Apple对象本身没有weight属性。/因为Apple的父类有weight属性,也可以访问Apple对象的属性a.weight=56;/调用Apple对象的info方法();,该程序的输出结果为:我是一个水果!重56.0g!,21:19,6.1类的继承6.1.1继承的特点,21:19,6.1类的继承6.1.2重写父类的方法,子类扩展了父类,子类是一个特殊的父类。大部分时候,子类总是以父类为基础,额外增加新的属性和方法。但有一种情况例外:子类需要重写父类的方法。例如,鸟类都包含了飞翔(fly)的方法,其中鸵鸟是一种特殊的鸟类,因此鸵鸟应该是鸟的子类,因此它也将从鸟类获得飞翔方法,但这个飞翔方法明显不适合鸵鸟,因此,鸵鸟需要重写鸟类的方法。下面程序先定义一个Bird类。,21:19,6.1类的继承6.1.2重写父类的方法,程序清单:chapter06test1Bird.java,packagechapter06.test1;publicclassBird/Bird类的fly方法publicvoidfly()System.out.println(我在天空里自由自在地飞翔.);,21:19,6.1类的继承6.1.2重写父类的方法,下面再定义一个Ostrich类,这个类扩展了Bird类,但重写了Bird类的fly方法。程序清单:chapter06test1Ostrich.java,packagechapter06.test1;publicclassOstrichextendsBird/重写Bird类的fly方法publicvoidfly()System.out.println(我只能在地上奔跑.);publicstaticvoidmain(Stringargs)/创建Ostrich对象Ostrichos=newOstrich();/执行Ostrich对象的fly方法,将输出我只能在地上奔跑.os.fly();,该程序的输出结果为:我只能在地上奔跑.,21:19,6.1类的继承6.1.2重写父类的方法,这种子类包含父类同名方法的现象被称为方法重写,也称为方法覆盖(Override)。可以说子类重写了父类的方法,也可以说子类覆盖了父类的方法。方法的重写要遵循“两同两小一大”。两同:方法名相同;形参列表相同。两小:子类方法返回值类型应比父类方法返回值类型更小(即子类)或相同;子类方法声明抛出的异常应比父类方法声明抛出的异常类更小或相同。一大:子类方法的访问控制权限应比父类方法更大或相等。,21:19,6.1类的继承6.1.2重写父类的方法,注意:覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法;不能一个是类方法,一个是实例方法,否则编译出错。当子类覆盖了父类方法后,子类的对象将无法直接访问父类中被覆盖的方法,如果需要访问,可以使用super(被覆盖的是实例方法)或者父类名(被覆盖的是类方法)作为调用者来调用父类被覆盖的方法。如果父类方法具有private访问权限,则该方法对其子类是隐藏的,因此其子类无法访问该方法,也就无法重写该方法;如果子类定义了一个与父类private方法具有相同方法名、相同形参列表、相同返回值类型的方法,依然不是重写,只是在子类中重新定义了一个新方法。,21:19,6.1类的继承6.1.3父类实例的super引用,(1)通过super引用调用父类被覆盖的方法如果需要在子类中调用父类被覆盖的实例方法,可以通过关键字super作为调用者来调用父类被覆盖的方法。super是Java提供的一个关键字,它是直接父类的默认引用。例如,为上面的Ostrich类添加callOverridedMethod方法,在其中调用Bird类被覆盖的fly方法。完整的Ostrich类代码如下。程序清单:chapter06test1Ostrich.java,21:19,6.1类的继承6.1.3父类实例的super引用,packagechapter06.test1;publicclassOstrichextendsBird/重写Bird类的fly方法publicvoidfly()System.out.println(我只能在地上奔跑.);publicvoidcallOverridedMethod()/在子类方法中通过super来显式调用父类被覆盖的方法。super.fly();publicstaticvoidmain(Stringargs)/创建Ostrich对象Ostrichos=newOstrich();/执行Ostrich对象的fly方法,将输出我只能在地上奔跑.os.fly();os.callOverridedMethod();,该程序的输出结果为:我只能在地上奔跑.我在天空里自由自在地飞翔.,21:19,6.1类的继承6.1.3父类实例的super引用,21:19,6.1类的继承6.1.3父类实例的super引用,21:19,6.1类的继承6.1.3父类实例的super引用,(2)通过super引用访问父类的属性如果子类定义了和父类同名的属性,也会发生子类属性覆盖父类属性的情形。正常情况下,子类里定义的方法访问该属性,都是访问子类属性,无法访问到父类被覆盖的属性。但在子类定义的实例方法中可以通过super引用来访问父类被覆盖的属性。详见下面的例子程序清单:chapter06SubClass.java,21:19,6.1类的继承6.1.3父类实例的super引用,packagechapter06;classBaseClasspublicinta=5;publicclassSubClassextendsBaseClasspublicinta=7;publicvoidaccessOwner()System.out.println(a);publicvoidaccessBase()/通过super来访问方法调用者对应的父类对象System.out.println(super.a);publicstaticvoidmain(Stringargs)SubClasssc=newSubClass();/直接访问SubClass对象的a属性将会输出7System.out.println(sc.a);sc.accessOwner();/输出7sc.accessBase();/输出5,该程序的输出结果为:775,21:19,6.1类的继承6.1.4调用父类的构造器,(1)通过super引用调用父类的构造器在一个构造器中调用另一个重载的构造器要使用this引用来调用。在子类构造器中调用父类构造器要使用super引用来调用。详见下面的例子。程序清单:chapter06test1Sub.java,21:19,6.1类的继承6.1.4调用父类的构造器,packagechapter06.test1;classBasepublicdoublesize;publicStringname;publicBase(doublesize,Stringname)this.size=size;=name;,publicclassSubextendsBasepublicStringcolor;publicSub(doublesize,Stringname,Stringcolor)/通过super调用来调用父类构造器的初始化过程super(size,name);this.color=color;publicstaticvoidmain(Stringargs)Subs=newSub(5.6,测试对象,红色);/输出Sub对象的三个属性System.out.println(s.size+-++-+s.color);,该程序的输出结果为:5.6-测试对象-红色,21:19,6.1类的继承6.1.4调用父类的构造器,(2)构造器的调用顺序在调用子类的构造器创建一个子类实例时,父类构造器总会在子类构造器之前执行;不仅如此,执行父类构造器时,系统会再次上溯执行其父类的构造器,;以此类推,创建任何Java对象,最先执行的总是java.lang.Object类的构造器。详见下面的例子。程序清单:chapter06test1Wolf.java,21:19,6.1类的继承6.1.4调用父类的构造器,packagechapter06.test1;classCreaturepublicCreature()System.out.println(Creature无参数的构造器);classAnimalextendsCreaturepublicAnimal(Stringname)System.out.println(Animal带一个参数的构造器,该动物的name为+name);publicAnimal(Stringname,intage)/使用this调用同一个重载的构造器this(name);System.out.println(Animal带2个参数的构造器,其age为+age);,publicclassWolfextendsAnimalpublicWolf()/显式调用父类有2个参数的构造器super(土狼,3);System.out.println(Wolf无参数的构造器);publicstaticvoidmain(Stringargs)newWolf();,该程序的输出结果为:Creature无参数的构造器Animal带一个参数的构造器,该动物的name为土狼Animal带2个参数的构造器,其age为3Wolf无参数的构造器,21:19,6.2多态,Java引用变量有两个类型:一个是编译时的类型,一个是运行时的类型,编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给该变量的对象决定。如果编译时类型和运行时的类型不一致,这就有可能出现所谓的多态(Polymorphism)。,21:19,6.2多态6.2.1多态性,先看以下例子。程序清单:chapter06test2SubClass.java,packagechapter06.test2;classBaseClasspublicintbook=6;publicvoidbase()System.out.println(父类的普通方法);publicvoidtest()System.out.println(父类的被覆盖的方法);,publicclassSubClassextendsBaseClass/重新定义一个book实例属性覆盖父类的book实例属性publicStringbook=轻量级J2EE企业应用实战;publicvoidtest()System.out.println(子类的覆盖父类的方法);publicvoidsub()System.out.println(子类的普通方法);publicstaticvoidmain(Stringargs)/下面编译时类型和运行时类型完全一样,因此不存在多态BaseClassbc=newBaseClass();/输出6System.out.println(bc.book);/下面两次调用将执行BaseClass的方法bc.base();bc.test();,该程序的输出结果为:6父类的普通方法父类的被覆盖的方法轻量级J2EE企业应用实战父类的普通方法子类的覆盖父类的方法子类的普通方法6父类的普通方法子类的覆盖父类的方法,21:19,6.2多态6.2.1多态性,packagechapter06.test2;classBaseClasspublicintbook=6;publicvoidbase()System.out.println(父类的普通方法);publicvoidtest()System.out.println(父类的被覆盖的方法);,/下面编译时类型和运行时类型完全一样,因此不存在多态SubClasssc=newSubClass();/输出轻量级J2EE企业应用实战System.out.println(sc.book);/下面调用将执行从父类继承到的base方法sc.base();/下面调用将执行从当前类的test方法sc.test();/下面调用将执行从当前类的sub方法sc.sub();/下面编译时类型和运行时类型不一样,多态发生BaseClassploymophicBc=newSubClass();/输出6表明访问的是父类属性System.out.println(ploymophicBc.book);/下面调用将执行从父类继承到的base方法ploymophicBc.base();/下面调用将执行当前类的test方法ploymophicBc.test();/因为ploymophicBc的编译类型是BaseClass,BaseClass类没有/提供sub方法,所以下面代码编译时会出现错误。/ploymophicBc.sub();,该程序的输出结果为:6父类的普通方法父类的被覆盖的方法轻量级J2EE企业应用实战父类的普通方法子类的覆盖父类的方法子类的普通方法6父类的普通方法子类的覆盖父类的方法,21:19,6.2多态6.2.1多态性,上述例子中,第三个引用变量polymopicBc比较特殊,它的编译时类型是BaseClass,而运行时类型是SubClass,当调用该引用变量的test方法(BaseClass类定义了该方法,子类SubClass覆盖了父类的该方法),实际执行的是SubClass类中覆盖后的test方法,这就是多态。因为子类其实是一种特殊的父类,因此Java允许把一个子类对象直接赋给一个父类引用变量,无须任何类型转换,或者被称为向上转型(upcasting)、或上溯。向上转型由系统自动完成。,/下面编译时类型和运行时类型不一样,多态发生BaseClassploymophicBc=newSubClass();,21:19,6.2多态6.2.1多态性,21:19,6.2多态6.2.1多态性,当把一个子类对象直接赋给父类引用变量,例如上述例子中的语句“BaseClassploymophicBc=newSubClass();”,这个ploymophicBc引用变量的编译时类型是BaseClass,而运行时类型是SubClass,当运行时调用该引用变量的方法时,其方法行为总是像子类方法的行为,而不是像父类方法的行为,这将出现相同类型的变量、执行同一个方法时呈现出不同的行为特征,这就是多态。,21:19,6.2多态6.2.2引用变量的强制类型转换,C语言里也有强制类型转换。在Java程序里,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法(详见6.2.1节中被注释的代码),即使它实际所引用对象确实包含该方法。如果需要让这个引用变量来调用它运行时类型的方法,则必须把它强制类型转换成运行时类型。强制类型转换运算符是小括号,语法如下:(type)variable;,21:19,6.2多态6.2.2引用变量的强制类型转换,Java语言里的强制类型转换运算要注意:基本类型之间的转换只能在数值类型之间进行,这里所说的数值类型包括整数型、字符型和浮点型。但数值型不能和布尔型之间进行类型转换。引用类型之间的转换只能把一个父类变量转换成子类类型,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误。如果试图把一个父类实例转换成子类类型,则这个实例必须实际上是子类实例才行(即编译时类型为父类类型,而运行时类型是子类类型),否则将会在运行时引发ClassCastException异常。下面是进行强制类型转换的示范程序,下面程序详细说明了哪些情况可以进行类型转换,哪些情况不可以进行类型转换。,21:19,6.2多态6.2.2引用变量的强制类型转换,程序清单:chapter06test2TestConversion.java,packagechapter06.test2;publicclassTestConversionpublicstaticvoidmain(Stringargs)doubled=13.4;longl=(long)d;System.out.println(l);intin=5;/下面代码编译时出错:试图把一个数值型变量转换为boolean型,/编译时候会提示:不可转换的类型/booleanb=(boolean)in;Objectobj=Hello;/obj变量的编译类型为Object,是String类型的父类,可以强制类型转换/而且obj变量实际上类型也是String类型,所以运行时也可通过StringobjStr=(String)obj;System.out.println(objStr);/定义一个objPri变量,编译类型为Object,实际类型为IntegerObjectobjPri=newInteger(5);/objPri变量的编译类型为Object,是String类的父类,可以强制转换/而objPri变量实际上类型是Integer类型,所以下面代码运行时引发异常/Stringstr=(String)objPri;,该程序的输出结果为:13Hello,21:19,6.2多态6.2.2引用变量的强制类型转换,考虑到进行强制类型转换时可能会出现异常,因此进行类型转换前应先通过instanceof运算符来判断是否可以成功转换。例如上面的代码“Stringstr=(String)objPri;”运行时会引发ClassCastException异常,这是因为objPri不可转换成String类型,为了让程序更健壮,可以将代码修改为:if(objPriinstanceofString)Stringstr=(String)objPri;在进行强制类型转换前,先用instanceof运算符判断是否可以成功转换,从而避免出现ClassCastException异常。,21:19,6.2多态6.2.3instanceof运算符,instanceof和类型转换运算符一样,都是Java提供的运算符。其语法格式为:引用变量instanceof类(或接口)instanceof运算符的左操作数通常是一个引用类型的变量,右操作数通常是一个类(也可以是接口),它用于判断左边的对象是否是右边类(或者其子类)的实例。如果是返回true,否则返回false。下面的程序示范了instanceof运算符的用法。程序清单:chapter06test2TestInstanceof.java,21:19,6.2多态6.2.3instanceof运算符,packagechapter06.test2;publicclassTestInstanceofpublicstaticvoidmain(Stringargs)/声明hello为Object类,则hello的编译类型是Object,Object是所有类的父类/但hello变量的实际类型是StringObjecthello=Hello;/String是Object类的子类,所以返回true。System.out.println(字符串是否是Object类的实例:+(helloinstanceofObject);/返回true。System.out.println(字符串是否是String类的实例:+(helloinstanceofString);/返回false。System.out.println(字符串是否是Math类的实例:+(helloinstanceofMath);/String实现了Comparable接口,所以返回true。System.out.println(字符串是否是Comparable接口的实例:+(helloinstanceofComparable);Stringa=Hello;/String类既不是Math类,也不是Math类的父类,所以下面代码编译通不过/System.out.println(字符串是否是Math类的实例:+(ainstanceofMath);,该程序的输出结果为:字符串是否是Object类的实例:true字符串是否是String类的实例:true字符串是否是Math类的实例:false字符串是否是Comparable接口的实例:true,21:19,6.3继承和组合6.3.1使用继承的注意事项,继承是实现类重用的重要手段,但继承也带来了一个最大的坏处:破坏封装。组合是实现类重用的另一种方式。下面介绍继承和组合之间的练习和区别。子类扩展父类时,子类将可以从父类继承得到属性和方法,如果访问权限允许,子类将可以直接访问父类的属性和方法,相当于子类可以直接复用父类的属性和方法,确实非常方便。继承带来了高度复用的同时,也带来了一个严重的问题:继承严重地破坏了父类的封装性。前面介绍封装时提到:每个类都应该封装它内部信息和实现细节,而只暴露必要的方法给其他类使用。但在继承关系中,子类可以直接访问父类的属性和方法,从而造成子类和父类的严重耦合。,21:19,6.3继承和组合6.3.1使用继承的注意事项,为了保证父类良好的封装性,不会被子类随意改变,设计父类通常应该遵循如下规则:尽量隐藏父类的内部数据。不要让子类可以随意访问、修改父类方法。尽量不要在父类构造器中调用将要被子类重写的方法。如果想把某些类设置成最终类,即不再派生出子类,则可以用final修饰这个类。到底何时需要从父类派生新的子类?不仅需要保证子类是一种特殊的父类,而且还需要具备以下两个条件之一:子类需要额外增加属性,而不仅仅是属性值的改变。子类需要增加自己独有的行为方式(包括增加新的方法或重写父类的方法)。,21:19,6.3继承和组合6.3.2利用组合实现复用,继承要表达的是一种“是(is-a)”的关系,而组合表达的是“有(has-a)”的关系。【提问】试从现实生活中例举继承和组合的例子。假设有三个类:Animal、Wolf和Bird,它们之间有如下图所示的继承树。,21:19,6.3继承和组合6.3.2利用组合实现复用,程序清单:chapter06test3TestInherit.java,packagechapter06.test3;classAnimalprivatevoidbeat()System.out.println(心脏跳动.);publicvoidbreath()beat();System.out.println(吸一口气,吐一口气,呼吸中.);/继承Animal,直接复用父类的breath方法classBirdextendsAnimalpublicvoidfly()System.out.println(我在天空自在的飞翔.);,/继承Animal,直接复用父类的breath方法classWolfextendsAnimalpublicvoidrun()System.out.println(我在陆地上的快速奔跑.);publicclassTestInheritpublicstaticvoidmain(Stringargs)Birdb=newBird();b.breath();b.fly();Wolfw=newWolf();w.breath();w.run();,21:19,6.3继承和组合6.3.2利用组合实现复用,如果仅从软件复用的角度,将上面三个类的定义改为如下形式也可实现相同的复用。程序清单:chapter06TestComposite.java,21:19,6.3继承和组合6.3.2利用组合实现复用,packagechapter06;classAnimalpri
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 渤海石油职业学院《思想政治教育专业导论与创业基础》2023-2024学年第一学期期末试卷
- 兰州石化职业技术大学《应用回归分析》2023-2024学年第一学期期末试卷
- 贵州应用技术职业学院《药物分析》2023-2024学年第一学期期末试卷
- 漳州理工职业学院《食品质量检验技术》2023-2024学年第一学期期末试卷
- 开放大学学前教育社会实践考核表范文
- 河南大学《国画基础》2023-2024学年第一学期期末试卷
- 长垣烹饪职业技术学院《世界现代设计史》2023-2024学年第一学期期末试卷
- 世界读书节活动方案
- 天猫圣诞节活动策划方案
- 天津公司宣传片策划方案
- T/CI 307-2024用于疾病治疗的间充质干细胞质量要求
- 《新生儿高胆红素血症诊治指南(2025)》解读课件
- 《艺术家心中的自画像》课件
- (2025)汽车驾驶员(技师)考试题及答案
- 2025春季学期国开电大本科《商务英语3》一平台在线形考(综合测试)试题及答案
- 针对越南学生的对外汉语课件设计
- 智能营销传播系统技术需求
- 新大学语文试题及答案
- 2025年农业经理人高级工考试题库(附答案)
- 四川省2024普通高校招生本科二批调档线理科
- 众筹合作协议书范例
评论
0/150
提交评论