多态的前提是必须有子父类关系或者类实现接口关系,否则无法完成多态。在使用多态后的父类引用变量调用方法时,会调用子类重写后的方法。
文字再怎么讲,都不够生动,直接用代码来体现
老爸要喝酒,那今天喝什么酒呢,
publicclassWine{publicvoiddrinkWine(){ System.out.println("===今天我要喝什么酒呢===="); Wine(); }publicvoidWine(){ System.out.println("===看看俺今天能喝啥子哟===="); }}
publicclassJNCextendsWine{/**
* @desc 子类重载父类方法
* 父类中不存在该方法,向上转型后,父类是不能引用该方法的
* @param a
* @return void
*/public void drinkWine(Stringa){System.out.println("======今天我要喝剑南春====");Wine(); }/**
* 子类重写父类方法
* 指向子类的父类引用调用Wine时,必定是调用该方法
*/public voidWine(){System.out.println("=====剑南春喝上啦,好开森====="); }}
publicclassTest{publicstaticvoidmain(String[] args){ Wine a =newJNC(); a.drinkWine(); a.Wine(); Wine b =newWine(); b.drinkWine(); b.Wine(); JNC c=newJNC(); c.drinkWine("qq"); }}
进群:697699179可以获取Java各类入门学习资料!
这是我的微信公众号【编程study】各位大佬有空可以关注下,每天更新Java学习方法,感谢!
学习中遇到问题有不明白的地方,推荐加小编Java学习群:697699179内有视频教程 ,直播课程 ,等学习资料,期待你的加入
先来看看这一段,
Wine a =newJNC();a.drinkWine();a.Wine();
子类剑南春中的drinkWine带有参数,而父类中的drinkWine不带有参数,即父类不存在这个方法
运行的时候,调用的是父类的drinkWine,先输出了
===今天我要喝什么酒呢====
之后继续调用Wine方法,这个时候是去了子类中,指向子类的父类引用调用Wine时,必定是调用子类中的方法,于是输出了
=====剑南春喝上啦,好开森=====
上面的Wine和JNC中的方法,都没有带Static,如果加上Static呢,看一下代码和运行的结果
classWine{publicstaticvoiddrinkWine(){ System.out.println("===今天我要喝什么酒呢===="); Wine(); }publicstaticvoidWine(){ System.out.println("===看看俺今天能喝啥子哟===="); }}classJNCextendsWine{publicstaticvoiddrinkWine(String a){ System.out.println("======今天我要喝剑南春===="); Wine(); }publicstaticvoidWine(){ System.out.println("=====剑南春喝上啦,好开森====="); }}classTest{publicstaticvoidmain(String[] args){ Wine a =newJNC(); a.drinkWine(); a.Wine(); }}
可以看到,静态方法,即使向上转型,也只能调用自己的方法啦
上面比较的是子类和父类的方法,在非静态方法和静态方法,父类引用子类的方法,非静态方法下可以调用子类同名的构造函数方法,不能调用不一样的构造方法
静态方法中,子类向上转型后,父类引用都不能进行调用子类的方法
下面来给父类和子类一些变量,以及一些方法,方法都是非静态的
父类,定义了一些姓名,年龄,兴趣爱好等的变量
和一些say和hobby的方法
publicclassFather{privateString fathername;privateintfatherage;privateString fahterhobby;publicvoidsay(){ System.out.println("==我是你爸爸真伟大,养你这么大=="); myhobby(); }publicvoidmyhobby(){ System.out.println("==我是你爸爸真伟大,只要你妈妈=="); }publicFather(){super(); }publicFather(String fathername,intfatherage, String fahterhobby){this.fathername = fathername;this.fatherage = fatherage;this.fahterhobby = fahterhobby; }//省略getters and setters@OverridepublicStringtoString(){return"Father{"+"fathername='"+ fathername +'\''+", fatherage="+ fatherage +", fahterhobby='"+ fahterhobby +'\''+'}'; }publicStringtoString(String fathername,intfatherage, String fahterhobby){return"Father{"+"fathername='"+ fathername +'\''+", fatherage="+ fatherage +", fahterhobby='"+ fahterhobby +'\''+'}'; }}
子类和父类差不多,其实不应该定义一样的变量,虽然名称改了一下
publicclassSonextendsFather{publicvoidsay(){ System.out.println("==爸爸我要出去玩==="); }publicvoidsay(String s){ System.out.println("==爸爸我要出去玩==="+s); }publicvoidmyhobby(String aaa){ System.out.println("==爸爸给我买这个玩具: "+ aaa); }privateString sonname;privateintsonage;privateString sonhobby;publicSon(String sonname,intsonage, String sonhobby){this.sonname = sonname;this.sonage = sonage;this.sonhobby = sonhobby; }publicSon(String fathername,intfatherage, String fahterhobby, String sonname,intsonage, String sonhobby){super(fathername, fatherage, fahterhobby);this.sonname = sonname;this.sonage = sonage;this.sonhobby = sonhobby; }//省略getters and setters@OverridepublicStringtoString(String sonname,intsonage, String sonhobby){return"Son{"+"sonname='"+ sonname +'\''+", sonage="+ sonage +", sonhobby='"+ sonhobby +'\''+'}'; }}
测试:
主要测试如下:
子类中,对say()无参数的方法进行了改写,输出内容不一致了,且有自己新创建的say(String s)带有入参的方法
子类对myhobby也新增了,有了入参
子类中对toString方法也带有入参的
实例化子类对象,父类引用,即向上转型了,调用say(),这个方法子类中有; 调用myhobby(), 子类中没有myhobby(), 只有myhobby(String aaa) 然后还要调用toString(), 有参数和无参数的
publicclasstest{publicstaticvoidmain(String[] args){ Father father =newSon("张三",35,"LOL","张四",5,"Learn"); System.out.println("实例化一个Son对象,用父亲接收"); father.say(); father.myhobby();//代码报错// father.myhobby("LOL惊奇娃娃");System.out.println(father.toString()); System.out.println(father.toString("张三",35,"LOL")); System.out.println("\n"); Son son =newSon("张四",5,"Learn"); System.out.println("实例化一个Son对象,用Son接收"); son.say(); son.say("上海迪士尼"); son.myhobby(); son.myhobby("LOL惊奇娃娃"); System.out.println(son.toString("张四",5,"Learn")); }}
运行结果如下:
1. 父类引用调用say(), 由于子类中有这个方法,调用的是子类的这个方法;
调用myhobby();, 由于子类中没有这个方法,调用的是父类的这个方法;
调用子类中带有参数的方法,father.myhobby("LOL惊奇娃娃");代码直接报错了
调用toString(),分别是无参数和有参数,因为子类中只有三个有参数的,没有无参数的,就无参数返回的是父类的,有参数返回的是子类的
2. 子类引用指向子类对象,调用say()无参数的和有参数的,由于子类中都有,都是子类自己的方法进行返回
调用myobby()无参数的和有参数的,由于子类中没有无参数的,就去爸爸那儿找了找,返回了爸爸的爱好,子类中有带参数的,就返回了子类自己的
调用toString(3个参数略),就返回了自己的方法,如果调用不带参数的toString(),就是返回一个父亲中的方法了。。。
总结: 父类引用指向子类,调用返回的时候,看看自己家有没有啊,有啊,哦,不管了,先去儿子家找找,儿子有啊,儿子用你家的,儿子没有啊,回家用自己的方法吧
子类引用指向子类,调用返回的时候,先去自己(即儿子)方法中看看,我自己没有呀,去父亲方法中看看吧
上面看的继承中的父子关系是,爸爸有,儿子有,儿子有新的
下面继续看继承,论父子之间的关系之,爸爸没有,儿子有;
员工对象,只有一个mailCheck()方法,定义了一些变量
publicclassEmployee {privateStringname;privateStringaddress;privateintnumber;publicEmployee(Stringname,Stringaddress, intnumber) {//System.out.println("Employee 构造函数");this.name = name;this.address = address;this.number =number; }publicvoidmailCheck() { System.out.println("邮寄支票给: "+this.name +" "+this.address); } @OverridepublicStringtoString() {return"Employee{"+"name='"+ name +'\''+", address='"+ address +'\''+", number="+number+'}'; }//省略getters and setters
Salary对象继承了父类
publicclassSalaryextendsEmployee{privatedoubleyearsalary;// 全年工资publicdoublegetSalary(){returnyearsalary; }publicvoidsetSalary(doublesalary){if(salary >=0.0)this.yearsalary = salary; }publicdoublecomputePay(){ System.out.println("计算工资,付给:"+ getName());returnyearsalary/12; }publicSalary(String name, String address,intnumber,doubleyearsalary){super(name, address, number); setSalary(yearsalary); }publicvoidmailCheck(){ System.out.println("Salary 类的 mailCheck 方法 "); System.out.println("邮寄支票给:"+ getName()+" ,工资为:"+ yearsalary); }}
测试如下
publicclassDemo{publicstaticvoidmain(String [] args){ Salary s =newSalary("员工 A","北京",3,360000.00); s.mailCheck();doublesa = s.computePay(); System.out.println(sa); System.out.println("\n"); Employee e =newSalary("员工 B","上海",2,240000.00); e.mailCheck();doublesalary = ((Salary) e).computePay(); System.out.println(salary); }}
必要要强转 ((Salary) e).computePay();
问题来啦,我是父亲,我有两个儿子或者多个儿子呢,闹啥啊
publicclassAnimal{ void eat() {System.out.println("Animal"); }}publicclassCatextendsAnimal{ public void eat() {System.out.println("===我是猫咪我要吃鱼"); } public void work() {System.out.println("===我是猫咪我负责抓老鼠"); }}publicclassDogextendsAnimal{ public void eat() {System.out.println("====我是小狗我要吃骨头"); } public void work() {System.out.println("====我是小狗我负责看家"); }}
publicclassTest{publicstaticvoidmain(String[] args){ show(newCat());// 以 Cat 对象调用 show 方法System.out.println("\n"); show(newDog());// 以 Dog 对象调用 show 方法System.out.println("\n"); Animal a =newCat();// 向上转型a.eat();// 调用的是 Cat 的 eatCat c = (Cat)a;// 向下转型c.work();// 调用的是 Cat 的 work}publicstaticvoidshow(Animal animal){ animal.eat();// 类型判断if(animalinstanceofCat) {// 猫做的事情Cat c = (Cat)animal; c.work(); }elseif(animalinstanceofDog) {// 狗做的事情Dog c = (Dog)animal; c.work(); } }}