06-面向对象:继承和多态

上传人:gu****n 文档编号:242970682 上传时间:2024-09-13 格式:PPT 页数:43 大小:1.73MB
返回 下载 相关 举报
06-面向对象:继承和多态_第1页
第1页 / 共43页
06-面向对象:继承和多态_第2页
第2页 / 共43页
06-面向对象:继承和多态_第3页
第3页 / 共43页
点击查看更多>>
资源描述
单击此处编辑母版标题样式,单击此处编辑母版文本样式,第二级,第三级,第四级,第五级,43,*,Java,程序设计,重庆交大,上一章内容回顾,5.,面向对象:构造方法,封装与隐藏,构造器,理解构造器,构造器的重载,封装,理解封装,访问控制符,包,(package),包及其作用,package,和,import,语句,Java,的常用包,9/13/2024,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.3,instanceof,运算符,6.3,继承和组合,6.4,课后作业,9/13/2024,6.1,类的继承,6.1.1,继承的特点,继承是面向对象三大特征之一,也是实现软件复用的重要手段。,Java,的继承通过关键字,extends,来实现,实现继承的类称为,子类,,被继承的类称为,基类,、,超类,、,父类,。父类与子类的关系,是一种,一般和特殊,的关系。例如水果和苹果的关系,苹果继承了水果,苹果是水果的子类,则苹果是一种特殊的水果。,因为子类是一种特殊的父类,因此父类包含的范围总比子类包含的范围要大,,因此父类是大类,子类是小类,。,Java,的继承是,单继承,,每个类最多只有一个直接父类。,9/13/2024,6.1,类的继承,6.1.1,继承的特点,Java,里子类继承父类的语法格式如下:,修饰符, class subclass,extends,superclass,/,类定义部分,“extends”,的含义是子类扩展了父类,将可以获得父类的全部属性和方法,但子类不能获得父类构造方法。,以下程序示范了子类继承父类的特点。,9/13/2024,6.1,类的继承,6.1.1,继承的特点,程序清单:chapter06test1Fruit.java、Apple.java,package,chapter06.test1;,public,class,Fruit ,public,double,weight;,public,void,info() ,System.out.println(我是一个水果!重, + weight + g!);,package,chapter06.test1;,public,class,Apple,extends,Fruit ,public,static,void,main(String,args,) ,/,创建Apple的对象,Apple a =,new,Apple();,/,Apple对象本身没有weight属性,。,/,因为Apple的父类有weight属性,也可以访问Apple对象的属性,a.weight,= 56;,/,调用Apple对象的info方法,a.info,();,该程序的输出结果为:,我是一个水果!重,56.0g,!,9/13/2024,6.1,类的继承,6.1.1,继承的特点,9/13/2024,6.1,类的继承,6.1.,2,重写父类的方法,子类扩展了父类,子类是一个特殊的父类。大部分时候,子类总是以父类为基础,额外增加新的属性和方法。但有一种情况例外:,子类需要重写父类的方法,。,例如,鸟类都包含了飞翔,(fly),的方法,其中鸵鸟是一种特殊的鸟类,因此鸵鸟应该是鸟的子类,因此它也将从鸟类获得飞翔方法,但,这个飞翔方法明显不适合鸵鸟,因此,鸵鸟需要重写鸟类的方法,。,下面程序先定义一个,Bird,类。,9/13/2024,6.1,类的继承,6.1.,2,重写父类的方法,程序清单:,chapter06test1Bird.java,package,chapter06.test1;,public,class,Bird ,/,Bird类的fly方法,public,void,fly() ,System.out.println(我在天空里自由自在地飞翔,.);,9/13/2024,6.1,类的继承,6.1.,2,重写父类的方法,下面再定义一个,Ostrich,类,这个类扩展了,Bird,类,但重写了,Bird,类的,fly,方法。,程序清单:,chapter06test1Ostrich.java,package,chapter06.test1;,public,class,Ostrich,extends,Bird ,/,重写Bird类的fly方法,public,void,fly() ,System.out.println(我只能在地上奔跑,.);,public,static,void,main(String,args,) ,/,创建Ostrich对象,Ostrich,os,=,new,Ostrich();,/,执行Ostrich对象的fly方法,将输出我只能在地上奔跑,.,os.fly,();,该程序的输出结果为:,我只能在地上奔跑,.,9/13/2024,6.1,类的继承,6.1.,2,重写父类的方法,这种子类包含父类同名方法的现象被称为,方法重写,,也称为,方法覆盖,(Override),。可以说子类重写了父类的方法,也可以说子类覆盖了父类的方法。方法的重写要遵循,“两同两小一大”,。,两同,:,方法名相同;,形参列表相同。,两小,:,子类方法返回值类型应比父类方法返回值类型更小,(,即子类,),或相同;,子类方法声明抛出的异常应比父类方法声明抛出的异常类更小或相同。,一大,:,子类方法的访问控制权限应比父类方法更大或相等。,9/13/2024,6.1,类的继承,6.1.,2,重写父类的方法,注意:,覆盖方法和被覆盖方法要么都是类方法,要么都是实例方法;不能一个是类方法,一个是实例方法,否则编译出错。,当子类覆盖了父类方法后,子类的对象将无法直接访问父类中被覆盖的方法,如果需要访问,可以使用,super(,被覆盖的是实例方法,),或者,父类名,(,被覆盖的是类方法,),作为调用者来调用父类被覆盖的方法。,如果父类方法具有,private,访问权限,则该方法对其子类是隐藏的,因此其子类无法访问该方法,也就无法重写该方法;如果子类定义了一个与父类,private,方法具有相同方法名、相同形参列表、相同返回值类型的方法,依然不是重写,只是在子类中重新定义了一个新方法。,9/13/2024,6.1,类的继承,6.1.3,父类实例的super引用,(1),通过,super,引用调用父类被覆盖的方法,如果需要在子类中调用父类被覆盖的实例方法,可以通过关键字,super,作为调用者来调用父类被覆盖的方法。,super,是,Java,提供的一个关键字,它是直接父类的默认引用。,例如,为上面的,Ostrich,类添加,callOverridedMethod,方法,在其中调用,Bird,类被覆盖的,fly,方法。,完整的,Ostrich,类代码如下。,程序清单:,chapter06test1Ostrich.java,9/13/2024,6.1,类的继承,6.1.3,父类实例的super引用,package,chapter06.test1;,public,class,Ostrich,extends,Bird ,/,重写Bird类的fly方法,public,void,fly() ,System.out.println(我只能在地上奔跑,.);,public,void,callOverridedMethod,() ,/,在子类方法中通过super来显式调用父类被覆盖的方法,。,super,.fly,();,public,static,void,main(String,args,) ,/,创建Ostrich对象,Ostrich,os,=,new,Ostrich();,/,执行Ostrich对象的fly方法,将输出我只能在地上奔跑,.,os.fly,();,os.callOverridedMethod,();,该程序的输出结果为:,我只能在地上奔跑.,我在天空里自由自在地飞翔.,9/13/2024,6.1,类的继承,6.1.3,父类实例的super引用,9/13/2024,6.1,类的继承,6.1.3,父类实例的super引用,9/13/2024,6.1,类的继承,6.1.3,父类实例的super引用,(2),通过,super,引用访问父类的属性,如果子类定义了和父类同名的属性,也会发生,子类属性覆盖父类属性,的情形。正常情况下,子类里定义的方法访问该属性,都是访问子类属性,无法访问到父类被覆盖的属性。但在子类定义的实例方法中可以通过,super,引用,来访问父类被覆盖的属性。详见下面的例子,程序清单:,chapter06SubClass.java,9/13/2024,6.1,类的继承,6.1.3,父类实例的super引用,package,chapter06;,class,BaseClass,public,int,a = 5;,public,class,SubClass,extends,BaseClass,public,int,a = 7;,public,void,accessOwner,() ,System.out.println(a,);,public,void,accessBase,() ,/,通过super来访问方法调用者对应的父类对象,System.out.println(,super,.a,);,public,static,void,main(String,args,) ,SubClass,sc =,new,SubClass,();,/直接访问SubClass对象的a属性将会输出7,System.out.println(sc.a,);,sc.accessOwner,();,/输出7,sc.accessBase,();,/输出5,该程序的输出结果为:,7,7,5,9/13/2024,6.1,类的继承,6.1.4,调用父类的构造器,(1),通过,super,引用调用父类的构造器,在一个构造器中调用另一个重载的构造器要使用,this,引用,来调用。在子类构造器中调用父类构造器要使用,super,引用,来调用。详见下面的例子。,程序清单:,chapter06test1Sub.java,9/13/2024,6.1,类的继承,6.1.4,调用父类的构造器,package,chapter06.test1;,class,Base ,public,double,size;,public,String name;,public,Base(double,size, String name) ,this,.size,= size;,this,.name,= name;,public,class,Sub,extends,Base ,public,String color;,public,Sub(,double,size, String name, String color) ,/,通过super调用来调用父类构造器的初始化过程,super,(size, name);,this,.color,= color;,public,static,void,main(String,args,) ,Sub s =,new,Sub(5.6, ,测试对象, ,红色,);,/,输出Sub对象的三个属性,System.out.println(s.size,+ - +,s.name,+ - +,s.color,);,该程序的输出结果为:,5.6-,测试对象,-,红色,9/13/2024,6.1,类的继承,6.1.4,调用父类的构造器,(2),构造器的调用顺序,在调用子类的构造器创建一个子类实例时,,父类构造器总会在子类构造器之前执行,;不仅如此,执行父类构造器时,系统会再次上溯执行其父类的构造器,,;以此类推,创建任何,Java,对象,最先执行的总是,java.lang.Object,类的构造器。详见下面的例子。,程序清单:,chapter06test1Wolf.java,9/13/2024,6.1,类的继承,6.1.4,调用父类的构造器,package,chapter06.test1;,class,Creature ,public,Creature() ,System.out.println(Creature无参数的构造器,);,class,Animal,extends,Creature ,public,Animal(String,name) ,System.out.println(Animal带一个参数的构造器,该动物的name为, + name);,public,Animal(String,name,int,age) ,/,使用this调用同一个重载的构造器,this,(name,);,System.out.println(Animal带2个参数的构造器,其age为 + age);,public,class,Wolf,extends,Animal ,public,Wolf() ,/显式调用父类有2个参数的构造器,super,(土狼, 3);,System.out.println(Wolf无参数的构造器,);,public,static,void,main(String,args,) ,new,Wolf();,该程序的输出结果为:,Creature,无参数的构造器,Animal,带一个参数的构造器,该动物的,name,为土狼,Animal,带,2,个参数的构造器,其,age,为,3,Wolf,无参数的构造器,9/13/2024,6.2,多态,Java,引用变量有,两个类型,:一个是,编译时的类型,,一个是,运行时的类型,,,编译时的类型由声明该变量时使用的类型决定,运行时的类型由实际赋给该变量的对象决定,。,如果编译时类型和运行时的类型不一致,,这就有可能出现所谓的,多态,(Polymorphism),。,9/13/2024,6.2,多态,6.2.1,多态性,先看以下例子,。,程序清单:chapter06test2SubClass.java,package,chapter06.test2;,class,BaseClass,public,int,book = 6;,public,void,base() ,System.out.println(父类的普通方法,);,public,void,test() ,System.out.println(父类的被覆盖的方法,);,public,class,SubClass,extends,BaseClass,/,重新定义一个book实例属性覆盖父类的book实例属性,public,String book = 轻量级J2EE企业应用实战;,public,void,test() ,System.out.println(子类的覆盖父类的方法,);,public,void,sub() ,System.out.println(子类的普通方法,);,public,static,void,main(String,args,) ,/,下面编译时类型和运行时类型完全一样,因此不存在多态,BaseClass,bc,=,new,BaseClass,();,/,输出,6,System.out.println(bc.book,);,/,下面两次调用将执行BaseClass的方法,bc.base,();,bc.test,();,该程序的输出结果为:,6,父类的普通方法,父类的被覆盖的方法,轻量级,J2EE,企业应用实战,父类的普通方法,子类的覆盖父类的方法,子类的普通方法,6,父类的普通方法,子类的覆盖父类的方法,9/13/2024,6.2,多态,6.2.1,多态性,package,chapter06.test2;,class,BaseClass,public,int,book = 6;,public,void,base() ,System.out.println(父类的普通方法,);,public,void,test() ,System.out.println(父类的被覆盖的方法,);,/,下面编译时类型和运行时类型完全一样,因此不存在多态,SubClass,sc =,new,SubClass,();,/输出轻量级J2EE企业应用实战,System.out.println(sc.book,);,/,下面调用将执行从父类继承到的base方法,sc.base,();,/,下面调用将执行从当前类的test方法,sc.test,();,/,下面调用将执行从当前类的sub方法,sc.sub,();,/,下面编译时类型和运行时类型不一样,多态发生,BaseClass,ploymophicBc,=,new,SubClass,();,/,输出,6 ,表明访问的是父类属性,System.out.println(ploymophicBc.book,);,/,下面调用将执行从父类继承到的base方法,ploymophicBc.base,();,/,下面调用将执行当前类的test方法,ploymophicBc.test,();,/,因为ploymophicBc的编译类型是BaseClass,BaseClass类没有,/,提供sub方法,,,所以下面代码编译时会出现错误,。,/,ploymophicBc.sub,();,该程序的输出结果为:,6,父类的普通方法,父类的被覆盖的方法,轻量级,J2EE,企业应用实战,父类的普通方法,子类的覆盖父类的方法,子类的普通方法,6,父类的普通方法,子类的覆盖父类的方法,9/13/2024,6.2,多态,6.2.1,多态性,上述例子中,第三个引用变量,polymopicBc,比较特殊,它的编译时类型是,BaseClass,,而运行时类型是,SubClass,,当调用该引用变量的,test,方法,(,BaseClass,类定义了该方法,子类,SubClass,覆盖了父类的该方法,),,实际执行的是,SubClass,类中覆盖后的,test,方法,这就是,多态,。,因为子类其实是一种特殊的父类,因此,Java,允许把一个子类对象直接赋给一个父类引用变量,无须任何类型转换,或者被称为,向上转型,(,upcasting,),、或,上溯,。向上转型由系统自动完成,。,/,下面编译时类型和运行时类型不一样,多态发生,BaseClass,ploymophicBc,=,new,SubClass,();,9/13/2024,6.2,多态,6.2.1,多态性,9/13/2024,6.2,多态,6.2.1,多态性,当把一个子类对象直接赋给父类引用变量,例如上述例子中的语句“,BaseClass,ploymophicBc,= new,SubClass,();”,,这个,ploymophicBc,引用变量的编译时类型是,BaseClass,,而运行时类型是,SubClass,,当运行时调用该引用变量的方法时,其方法行为总是像子类方法的行为,而不是像父类方法的行为,这将出现相同类型的变量、执行同一个方法时呈现出不同的行为特征,这就是,多态,。,9/13/2024,6.2,多态,6.2.2,引用变量的强制类型转换,C,语言里也有强制类型转换。,在,Java,程序里,,引用变量只能调用它编译时类型的方法,而不能调用它运行时类型的方法,(,详见,6.2.1,节中被注释的代码,),,即使它实际所引用对象确实包含该方法。如果需要让这个引用变量来调用它运行时类型的方法,则必须把它,强制类型转换,成运行时类型。,强制类型转换,运算符,是,小括号,,语法如下:,(type) variable;,9/13/2024,6.2,多态,6.2.2,引用变量的强制类型转换,Java,语言里的强制类型转换运算要注意,:,基本类型之间的转换,只能在数值类型之间进行,这里所说的数值类型包括整数型、字符型和浮点型。但数值型不能和布尔型之间进行类型转换,。,引用类型之间的转换,只能把一个父类变量转换成子类类型,如果是两个没有任何继承关系的类型,则无法进行类型转换,否则编译时就会出现错误。如果试图把一个父类实例转换成子类类型,则这个实例必须实际上是子类实例才行,(,即编译时类型为父类类型,而运行时类型是子类类型,),,否则将会在运行时引发,ClassCastException,异常,。,下面是进行强制类型转换的示范程序,下面程序详细说明了哪些情况可以进行类型转换,哪些情况不可以进行类型转换,。,9/13/2024,6.2,多态,6.2.2,引用变量的强制类型转换,程序清单,:,chapter06test2TestConversion.java,package,chapter06.test2;,public,class,TestConversion,public,static,void,main(String,args,) ,double,d = 13.4;,long,l = (,long,) d;,System.out.println(l,);,int,in = 5;,/,下面代码编译时出错:试图把一个数值型变量转换为,boolean,型,,/,编译时候会提示,:,不可转换的类型,/,boolean,b = (,boolean)in,;,Object,obj,= Hello;,/,obj,变量的编译类型为,Object,,是,String,类型的父类,可以强制类型转换,/,而且,obj,变量实际上类型也是,String,类型,所以运行时也可通过,String,objStr,= (String),obj,;,System.out.println(objStr,);,/,定义一个,objPri,变量,编译类型为,Object,,实际类型为,Integer,Object,objPri,=,new,Integer(5);,/,objPri,变量的编译类型为,Object,,是,String,类的父类,可以强制转换,/,而,objPri,变量实际上类型是,Integer,类型,所以下面代码运行时引发异常,/String,str,= (String),objPri,;,该程序的输出结果为:,13,Hello,9/13/2024,6.2,多态,6.2.2,引用变量的强制类型转换,考虑到进行强制类型转换时可能会出现异常,因此进行类型转换前应先通过,instanceof,运算符来判断是否可以成功转换。例如上面的代码“String,str,= (String),objPri;”运行时会引发ClassCastException异常,这是因为objPri不可转换成String类型,为了让程序更健壮,可以将代码修改为,:,if,(objPri,instanceof,String),String,str,= (String),objPri,;,在进行强制类型转换前,先用,instanceof,运算符判断是否可以成功转换,从而避免出现ClassCastException异常,。,9/13/2024,6.2,多态,6.2.3,instanceof,运算符,instanceof,和类型转换运算符一样,都是Java提供的运算符,。,其,语法格式为:,引用变量,instanceof,类,(,或接口,),instanceof运算符的左操作数通常是一个引用类型的变量,右操作数通常是一个类(也可以是接口),它用于判断左边的对象是否是右边类(或者其子类)的实例。如果是返回true,否则返回false,。,下面的程序示范了instanceof运算符的用法,。,程序清单:chapter06test2TestInstanceof.java,9/13/2024,6.2,多态,6.2.3,instanceof,运算符,package,chapter06.test2;,public,class,TestInstanceof,public,static,void,main(String,args,) ,/,声明,hello,为,Object,类,则,hello,的编译类型是,Object,,,Object,是所有类的父类,/,但,hello,变量的实际类型是,String,Object hello = Hello;,/String,是,Object,类的子类,所以返回,true,。,System.out.println,(,字符串是否是,Object,类的实例:, + (,hello,instanceof,Object,);,/,返回,true,。,System.out.println,(,字符串是否是,String,类的实例:, + (,hello,instanceof,String,);,/,返回,false,。,System.out.println,(,字符串是否是,Math,类的实例:, + (,hello,instanceof,Math,);,/String,实现了,Comparable,接口,所以返回,true,。,System.out.println,(,字符串是否是,Comparable,接口的实例:, + (,hello,instanceof,Comparable,);,String a = Hello;,/String,类既不是,Math,类,也不是,Math,类的父类,所以下面代码编译通不过,/,System.out.println,(,字符串是否是,Math,类的实例:, + (,a,instanceof,Math,);,该程序的输出结果为:,字符串是否是,Object,类的实例:,true,字符串是否是,String,类的实例:,true,字符串是否是,Math,类的实例:,false,字符串是否是,Comparable,接口的实例:,true,9/13/2024,6.3,继承和组合,6.3.1,使用继承的注意事项,继承是实现类重用的重要手段,但继承也带来了一个最大的坏处:,破坏封装,。组合是实现类重用的另一种方式。下面介绍继承和组合之间的练习和区别,。,子类扩展父类时,子类将可以从父类继承得到属性和方法,如果访问权限允许,子类将可以直接访问父类的属性和方法,相当于子类可以直接复用父类的属性和方法,确实非常方便,。,继承带来了高度复用的同时,也带来了一个严重的问题:继承严重地破坏了父类的封装性。前面介绍封装时提到:每个类都应该封装它内部信息和实现细节,而只暴露必要的方法给其他类使用。但在继承关系中,子类可以直接访问父类的属性和方法,从而造成子类和父类的严重耦合,。,9/13/2024,6.3,继承和组合,6.3.1,使用继承的注意事项,为了保证父类良好的封装性,不会被子类随意改变,设计父类通常应该遵循如下规则:,尽量隐藏父类的内部数据。,不要让子类可以随意访问、修改父类方法。,尽量不要在父类构造器中调用将要被子类重写的方法。,如果想把某些类设置成最终类,即不再派生出子类,则可以用,final,修饰这个类。,到底何时需要从父类派生新的子类?不仅需要保证子类是一种特殊的父类,而且还需要具备以下两个条件之一:,子类需要额外增加属性,而不仅仅是属性值的改变。,子类需要增加自己独有的行为方式,(,包括增加新的方法或重写父类的方法,),。,9/13/2024,6.3,继承和组合,6.3.2,利用组合实现复用,继承,要表达的是一种,“是,(is-a)”,的关系,而,组合,表达的是,“,有,(has-a)”,的关系。,【,提问,】,试从现实生活中例举继承和组合的例子。,假设有三个类:,Animal,、,Wolf,和,Bird,,它们之间有如下图所示的继承树。,9/13/2024,6.3,继承和组合,6.3.2,利用组合实现复用,程序清单:,chapter06test3TestInherit.java,package,chapter06.test3;,class,Animal ,private,void,beat() ,System.out.println,(,心脏跳动,.);,public,void,breath() ,beat();,System.out.println,(,吸一口气,吐一口气,呼吸中,.);,/,继承,Animal,,直接复用父类的,breath,方法,class,Bird,extends,Animal ,public,void,fly() ,System.out.println,(,我在天空自在的飞翔,.);,/,继承,Animal,,直接复用父类的,breath,方法,class,Wolf,extends,Animal ,public,void,run() ,System.out.println,(,我在陆地上的快速奔跑,.);,public,class,TestInherit,public,static,void,main(String,args,) ,Bird b =,new,Bird();,b.breath,();,b.fly,();,Wolf w =,new,Wolf();,w.breath,();,w.run,();,9/13/2024,6.3,继承和组合,6.3.2,利用组合实现复用,如果,仅从软件复用的角度,,将上面三个类的定义改为如下形式也可实现相同的复用。,程序清单:,chapter06TestComposite.java,9/13/2024,6.3,继承和组合,6.3.2,利用组合实现复用,package,chapter06;,class,Animal ,private,void,beat() ,System.out.println(心脏跳动,.);,public,void,breath() ,beat();,System.out.println(吸一口气,吐一口气,呼吸中,.);,class,Bird ,/,将原来的父类嵌入原来的子类,作为子类的一个组合成分,private,Animal a;,public,Bird(Animal,a) ,this,.a,= a;,/,重新定义一个自己的breath方法,public,void,breath() ,/,直接复用Animal提供的breath方法来实现Bird的breath方法,。,a.breath,();,public,void,fly() ,System.out.println(我在天空自在的飞翔,.);,class,Wolf ,/,将原来的父类嵌入原来的子类,作为子类的一个组合成分,private,Animal a;,public,Wolf(Animal,a) ,this,.a,= a;,/,重新定义一个自己的breath方法,public,void,breath() ,/,直接复用Animal提供的breath方法来实现Bird的breath方法,a.breath,();,public,void,run() ,System.out.println(我在陆地上的快速奔跑,.);,public,class,TestComposite,public,static,void,main(String,args,) ,/,此时需要显式创建被嵌入的对象,Animal a1 =,new,Animal();,Bird b =,new,Bird(a1);,b.breath,();,b.fly,();,/,此时需要显式创建被嵌入的对象,Animal a2 =,new,Animal();,Wolf w =,new,Wolf(a2);,w.breath,();,w.run,();,9/13/2024,6.3,继承和组合,6.3.2,利用组合实现复用,对于上面定义的三个类:,Animal,、,Wolf,和,Bird,,它们对应的,UML,图如下图所示。,9/13/2024,6.4,课后作业,1. (,面向对象设计,),某项目涉及到的实体包括:,乐器,(instrument),:包含名称,(name),和品牌,(brand),属性,具有弹奏,(play),方法。,钢琴,(Piano),:一种特殊的乐器,新增按键数,(,keyNum,),属性,具有特有的弹奏,(play),方法。,小提琴,(Violin),:一种特殊的乐器,新增琴弦数,(,chordNum,),属性,具有特有的弹奏,(play),方法。,吉他,(Guitar),:一种特殊的乐器,新增按键数,(,keyNum,),属性,具有特有的弹奏,(play),方法。,手风琴,(Accordion),:一种特殊的乐器,新增琴弦数,(,chordNum,),属性,具有特有的弹奏,(play),方法。,上述,5,个类的类图如下图所示,请用,Java,代码实现这,5,个类,,(,方法的实现只需输出提示信息即可,),;另外再新建一个,Test,类,用于测试这,5,个类,要求充分测试多态。,9/13/2024,6.4,课后作业,9/13/2024,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!