1.多态的概念及条件
概念:一个事物在不同时刻体现的不同时态 宏观角度(现实世界): 水: 液态 气态 固态 微观角度: 内存的变化 多态的前提条件: 1)必须存在继承关系,没有继承关系,谈不上多态; 2)必须存在方法重写,因为子类需要覆盖父类的功能; 3)必须有父类引用只需向子类对象---向上转型 格式: class Fu{} class Zi extends Fu{ //方法重写 } Fu fu = new Zi() ;
2.多态的成员访问特点
1)成员变量(非静态) 编译看左,运行看左 2)成员方法(非静态) 编译看左,运行看右, 子类的方法将父类的方法覆盖了,所有使用的子类的功能 3)静态方法算不上方法重写---跟类相关,类名.方法名() 编译看左,运行看左 4)构造方法访问---由于多态还是需要继承的,所以分层初始化
//父类 class Fu{ int num = 100 ; public void show(){ System.out.println("show Fu"); } public Fu(){ System.out.println("Fu的无参构造方法"); } public static void method(){ System.out.println("method Fu"); } } //子类 class Zi extends Fu { public Zi(){ //super(); System.out.println("Zi的无参构造方法.."); } int num = 20; public void show() { System.out.println("show Zi..."); } public static void method(){ System.out.println("method Zi"); } } public class DuoTaiDemo { public static void main(String[] args){ //父类引用指向子类对象---"向上转型的东西" Fu fu = new Zi() ; System.out.println(fu.num);//编译没有报错,说明Fu类型中有num变量,输出100 fu.show() ;//输出show zi; Fu.method();//静态方法通过类名访问---非得使用对象名来访问,不建议,输出:method Fu Zi.method();//输出:Fu的无参构造方法 和 Zi的无参构造方法.. } }
3.多态的好处与弊端
多态的好处: 1)提高代码的复用性(由继承保证) 2)提高代码的扩展性(有多态保证:父类引用指向子类对象)---经常使用
//动物类 class Animal{ public void eat(){ System.out.println("动物都需吃"); } public void sleep(){ System.out.println("动物都需睡"); } } //子类 class Cat extends Animal { public void eat() { System.out.println("猫吃鱼"); } public void sleep() { System.out.println("猫躺着睡觉"); } } class Dog extends Animal { public void eat() { System.out.println("狗吃骨头"); } public void sleep() { System.out.println("狗趴着睡觉"); } } class Pig extends Animal { public void eat() { System.out.println("猪吃白菜"); } public void sleep() { System.out.println("猪侧着睡觉"); } }
//动物工具类 class AnimalTool{ //将构造方法私有化,目的外界类不能new private AnimalTool(){} //使用猫的功能 /*public static void useCat(Cat c){//形式参数类猫---实际传递猫的对象 c.eat(); c.sleep(); } //使用狗的功能 public static void useDog(Dog d){ d.eat(); d.sleep(); } public static void usePig(Pig p){ p.eat(); p.sleep(); }*/ //父类引用指向子类对象 public static void useAnimal(Animal a){//实际参数: Animal a = new Dog(); // Animal a = new Cat() ; Animal a = new Pig() ; a.eat(); //a.eat(); a.sleep(); } }
//测试类 public class DuoTaiDemo2 { public static void main(String[] args) { //多态可以提高代码的扩展性 //之前的写法 继承版 Cat c = new Cat() ; c.eat(); c.sleep(); Dog d = new Dog() ; d.eat(); d.sleep(); System.out.println("--------------------------------------") ; //优化 //提供一个静态方法,参数类型就是猫类型或者狗类型 useCat(c);//实际参数就猫类对象c useDog(d);//实际参数就是狗类对象d Pig p = new Pig() ; usePig(p) ; // System.out.println("-------------------------------------------"); //上面优化不好:因为当前有一个新的动物类怎么,那么需要提供静态的useXXX(XXX类型) //代码量大,而且上面方式:使用面向对象的思想方式 //继续优化 //定义一个类:动物工具类AnimalTool //定义在当前AnimalToo里面作为它的静态方法 /*AnimalTool.useCat(c); AnimalTool.useDog(d); AnimalTool.usePig(p);*/ System.out.println("======================================================"); //继续优化:还是一样,当有新的动物类增加.又需要提供对应的useXXX(XXX类型)方法 //使用多态的第三个前提条件:父类引用指向子类对象 AnimalTool.useAnimal(new Cat()); AnimalTool.useAnimal(c); AnimalTool.useAnimal(d); AnimalTool.useAnimal(new Dog()); AnimalTool.useAnimal(p); AnimalTool.useAnimal(new Pig()); } //使用猫的功能 public static void useCat(Cat c){//形式参数类猫---实际传递猫的对象 c.eat(); c.sleep(); } //使用狗的功能 public static void useDog(Dog d){ d.eat(); d.sleep(); } public static void usePig(Pig p){ p.eat(); p.sleep(); } }
多态的弊端: 不能访问子类的特有功能 解决方法: 1)创建具体的子类对象----在堆内存中new,消耗内存空间,不建议 子类new子类对象 2)将父类的引用强转转换为子类的引用 :强转类型转换的格式 Zi z = (Zi)f ; 子类型 变量名 = (子类型)父的引用;-------向下转型:前提:必须存在向上转型
//父类 class Father{ public void teach(){ System.out.println("教书育人!"); } } //子类 class Son extends Father{ public void teach(){ System.out.println("教徒弟怎么上分"); } //特有功能 public void playGame(){ System.out.println("会玩lol"); } } //测试类 public class DuoTaiDemo3 { public static void main(String[] args) { //多态去测试 //父类引用指向子类对象 Father father = new Son() ;//多态 father.teach() ;//编译看左,运行看右,存在 重写 // father.playGame() ;//playGame()子类的特有功能 System.out.println("-------------------------------------") ; //方式1 Son son = new Son() ;//不太好:在堆内存中new,消耗内存空间 son.playGame(); System.out.println("----------------------------------------"); //向下转型:前提:必须存在向上转型,它不需要重写去new Son s = (Son) father; s.playGame(); System.out.println("-------------------------------------"); if( father instanceof Son){ //instanceof :判断前面的这个对象是否为后面类型的实例 System.out.println("内存中就是的son的对象"); }else{ System.out.println("不是"); } } }
4.向下转型异常
向下转型使用不当,会出现运行时期异常--- ClassCastException:类转换异常 解决方案: 改动代码---因为考虑内存中和当前接收的引用类型不匹配! 看内存的变化