Java 多态学习笔记1. 多态的概念多态指的是同一个行为作用在不同对象上会产生不同的执行结果。在 Java 中多态通常体现为使用父类引用指向子类对象并通过父类引用调用被子类重写的方法程序运行时会根据对象的真实类型执行对应的方法。简单理解AnimalanewCat(元宝,2);a.eat();// 调用 Cat 重写后的 eat 方法AnimalbnewDog(小七,1);b.eat();// 调用 Dog 重写后的 eat 方法虽然变量a和b的编译类型都是Animal但它们实际指向的对象不同所以调用eat()时的结果也不同。2. 多态的实现条件Java 中实现运行时多态需要同时满足三个条件存在继承关系子类必须继承父类例如classCatextendsAnimal{}classDogextendsAnimal{}子类重写父类方法子类需要对父类中的方法进行重写例如Overridepublicvoideat(){System.out.println(name吃鱼~~~);}通过父类引用调用重写方法AnimalanimalnewCat(元宝,2);animal.eat();只有通过父类引用调用被重写的方法才能体现运行时多态。3. 多态示例classAnimal{Stringname;intage;publicAnimal(Stringname,intage){this.namename;this.ageage;}publicvoideat(){System.out.println(name吃饭);}}classCatextendsAnimal{publicCat(Stringname,intage){super(name,age);}Overridepublicvoideat(){System.out.println(name吃鱼~~~);}}classDogextendsAnimal{publicDog(Stringname,intage){super(name,age);}Overridepublicvoideat(){System.out.println(name吃骨头~~~);}}publicclassTestAnimal{publicstaticvoideatFood(Animalanimal){animal.eat();}publicstaticvoidmain(String[]args){CatcatnewCat(元宝,2);DogdognewDog(小七,1);eatFood(cat);eatFood(dog);}}运行结果元宝吃鱼~~~ 小七吃骨头~~~代码理解eatFood方法的参数类型是Animal因此它既可以接收Cat对象也可以接收Dog对象。publicstaticvoideatFood(Animalanimal){animal.eat();}在编译阶段编译器只知道animal是Animal类型在运行阶段JVM 会根据animal实际指向的对象类型决定调用哪个类中的eat()方法。这就是动态绑定也是 Java 多态的核心。4. 方法重写4.1 什么是重写方法重写指的是子类对父类中已有的方法进行重新实现。父类提供通用行为子类根据自身特点给出不同实现。classAnimal{publicvoideat(){System.out.println(动物吃饭);}}classCatextendsAnimal{Overridepublicvoideat(){System.out.println(猫吃鱼);}}4.2 方法重写规则方法重写需要注意以下规则方法名必须相同。参数列表必须相同。返回值类型一般相同如果不同必须满足父子类关系。子类方法的访问权限不能比父类方法更严格。private方法不能被重写。static方法不能被重写。final方法不能被重写。构造方法不能被重写。示例classAnimal{publicvoideat(){System.out.println(动物吃饭);}}classDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃骨头);}}4.3Override注解重写方法时建议加上Override注解。它可以帮助编译器检查当前方法是否真的构成重写。如果方法名写错、参数列表写错编译器会直接报错。Overridepublicvoideat(){System.out.println(猫吃鱼);}5. 重写和重载的区别对比项重写 Override重载 Overload发生位置父子类之间同一个类中或者父子类中方法名必须相同必须相同参数列表必须相同必须不同返回值类型通常相同或满足父子类关系可以不同但不能只靠返回值区分重载访问权限子类不能更严格没有这个限制多态类型运行时多态编译时多态绑定时机动态绑定静态绑定重点记忆重载看参数重写看父子类关系和方法原型。// 重载方法名相同参数不同publicvoidprint(intx){}publicvoidprint(Strings){}// 重写子类重新实现父类方法Overridepublicvoideat(){}6. 向上转型6.1 什么是向上转型向上转型指的是使用父类引用指向子类对象。语法父类类型 引用名new子类类型();示例AnimalanimalnewCat(元宝,2);animal的编译类型是Animal但实际指向的是Cat对象。6.2 向上转型的三种常见场景场景一直接赋值AnimalanimalnewCat(元宝,2);场景二方法传参publicstaticvoideatFood(Animalanimal){animal.eat();}eatFood(newCat(元宝,2));eatFood(newDog(小七,1));父类类型的参数可以接收不同子类对象代码更加灵活。场景三方法返回值publicstaticAnimalbuyAnimal(Stringtype){if(猫.equals(type)){returnnewCat(猫猫,1);}elseif(狗.equals(type)){returnnewDog(狗狗,1);}returnnull;}方法返回值类型是父类实际返回的可以是任意子类对象。6.3 向上转型的优点向上转型可以让代码更加统一、简单、灵活。例如publicstaticvoideatFood(Animalanimal){animal.eat();}这个方法不用关心传进来的是猫还是狗只要它是Animal的子类就可以调用。6.4 向上转型的限制向上转型后只能调用父类中声明过的方法不能直接调用子类特有的方法。AnimalanimalnewDog(小七,1);animal.eat();// 可以调用因为 Animal 中有 eat 方法// animal.bark(); // 编译失败因为 Animal 中没有 bark 方法7. 向下转型7.1 什么是向下转型向下转型指的是把父类引用重新转换成子类引用。AnimalanimalnewDog(小七,1);Dogdog(Dog)animal;dog.bark();向下转型通常用于调用子类特有方法。7.2 向下转型的风险向下转型不安全。如果父类引用实际指向的对象不是目标子类类型运行时会抛出ClassCastException。AnimalanimalnewDog(小七,1);Catcat(Cat)animal;// 运行时报错原因是animal实际指向的是Dog对象不能强制转换成Cat。7.3 使用instanceof提高安全性向下转型前建议使用instanceof判断对象真实类型。AnimalanimalnewDog(小七,1);if(animalinstanceofDog){Dogdog(Dog)animal;dog.bark();}if(animalinstanceofCat){Catcat(Cat)animal;cat.mew();}这样可以避免错误转换导致程序崩溃。8. 动态绑定和静态绑定8.1 静态绑定静态绑定也叫前期绑定指的是在编译阶段就能确定具体调用哪个方法。典型例子方法重载。publicvoidprint(intx){}publicvoidprint(Strings){}编译器根据传入参数类型决定调用哪个重载方法。8.2 动态绑定动态绑定也叫后期绑定指的是编译阶段不能确定具体调用哪个方法需要等程序运行时根据对象真实类型决定。典型例子方法重写。AnimalanimalnewCat(元宝,2);animal.eat();// 运行时调用 Cat 的 eat 方法动态绑定是多态能够实现的关键。9. 多态的好处9.1 降低代码复杂度不使用多态时可能需要大量if-else判断对象类型if(shape.equals(cycle)){cycle.draw();}elseif(shape.equals(rect)){rect.draw();}elseif(shape.equals(flower)){flower.draw();}使用多态后可以把不同对象统一放到父类数组中Shape[]shapes{newCycle(),newRect(),newCycle(),newRect(),newFlower()};for(Shapeshape:shapes){shape.draw();}调用者只需要调用draw()具体画什么由对象本身决定。9.2 提高代码扩展性如果新增一个图形类只需要继承Shape并重写draw()方法。classTriangleextendsShape{Overridepublicvoiddraw(){System.out.println(△);}}原来的调用逻辑基本不用修改扩展成本更低。9.3 让代码更符合面向对象思想多态让程序更关注“对象能做什么”而不是“对象具体是什么类型”。例如shape.draw();这行代码表达的是“让图形自己画出来”而不是由调用者判断它到底是圆形、矩形还是三角形。10. 多态的缺点和限制10.1 运行效率可能略低多态需要在运行时确定具体调用哪个方法相比编译阶段直接确定的方法调用效率可能略低。不过在大多数实际开发中这点性能差异通常不是主要问题代码的可维护性和可扩展性更重要。10.2 属性没有多态性Java 中的多态主要针对方法不针对属性。当父类和子类中存在同名属性时通过父类引用访问属性访问的是父类中的属性。classAnimal{publicStringnameAnimal;}classCatextendsAnimal{publicStringnameCat;}publicclassTest{publicstaticvoidmain(String[]args){AnimalanimalnewCat();System.out.println(animal.name);// Animal}}注意属性访问看引用类型方法调用看对象真实类型。10.3 构造方法没有多态性构造方法不能被继承也不能被重写因此构造方法不存在多态。11. 避免在构造方法中调用可被重写的方法在构造方法中调用可被子类重写的方法可能会产生隐藏问题。示例classB{publicB(){func();}publicvoidfunc(){System.out.println(B.func());}}classDextendsB{privateintnum1;Overridepublicvoidfunc(){System.out.println(D.func() num);}}publicclassTest{publicstaticvoidmain(String[]args){DdnewD();}}运行结果D.func() 0原因分析创建D对象时会先调用父类B的构造方法。父类构造方法中调用了func()由于动态绑定会调用子类D重写后的func()。但是此时子类对象还没有初始化完成num还没有被赋值为1所以打印的是默认值0。结论构造方法中尽量不要调用普通实例方法尤其是可能被子类重写的方法。可以调用的方法通常是private方法因为不能被重写。final方法因为不能被重写。简单、稳定、不依赖子类状态的方法。12. 多态常见易错点易错点一父类引用不能调用子类特有方法AnimalanimalnewDog(小七,1);// animal.bark(); // 编译失败解决方式先向下转型再调用。if(animalinstanceofDog){Dogdog(Dog)animal;dog.bark();}易错点二向下转型可能运行时报错AnimalanimalnewDog(小七,1);Catcat(Cat)animal;// ClassCastException转换前要先判断if(animalinstanceofCat){Catcat(Cat)animal;cat.mew();}易错点三属性没有多态AnimalanimalnewCat();System.out.println(animal.name);访问哪个属性取决于引用变量的类型而不是对象真实类型。易错点四private方法不能被重写classAnimal{privatevoideat(){}}子类中即使写了同名方法也不是重写。易错点五static方法不能被重写静态方法属于类不属于对象因此不参与运行时多态。易错点六final方法不能被重写classAnimal{publicfinalvoideat(){}}子类不能重写final修饰的方法。13. 多态记忆口诀继承是前提重写是核心父类引用是入口。 编译看左边运行看右边。 属性看左边方法看右边。 向上转型自动完成向下转型需要谨慎。 转型之前 instanceof避免异常更安全。解释编译看左边变量声明的类型决定能调用哪些成员。运行看右边对象真实类型决定重写方法的执行结果。属性看左边属性没有多态访问属性看引用类型。方法看右边被重写的方法具有多态调用结果看对象真实类型。14. 学习重点总结多态是同一个行为在不同对象上产生不同结果。多态的三个条件继承、重写、父类引用调用重写方法。方法重写发生在父子类之间方法重载主要看参数列表。向上转型可以让代码更灵活但不能调用子类特有方法。向下转型可以调用子类特有方法但存在类型转换风险。使用instanceof可以提高向下转型的安全性。多态可以降低代码复杂度提高扩展性。属性和构造方法不具备多态性。构造方法中尽量不要调用可能被子类重写的方法。多态的核心机制是动态绑定。
多态学习笔记
发布时间:2026/6/26 6:32:13
Java 多态学习笔记1. 多态的概念多态指的是同一个行为作用在不同对象上会产生不同的执行结果。在 Java 中多态通常体现为使用父类引用指向子类对象并通过父类引用调用被子类重写的方法程序运行时会根据对象的真实类型执行对应的方法。简单理解AnimalanewCat(元宝,2);a.eat();// 调用 Cat 重写后的 eat 方法AnimalbnewDog(小七,1);b.eat();// 调用 Dog 重写后的 eat 方法虽然变量a和b的编译类型都是Animal但它们实际指向的对象不同所以调用eat()时的结果也不同。2. 多态的实现条件Java 中实现运行时多态需要同时满足三个条件存在继承关系子类必须继承父类例如classCatextendsAnimal{}classDogextendsAnimal{}子类重写父类方法子类需要对父类中的方法进行重写例如Overridepublicvoideat(){System.out.println(name吃鱼~~~);}通过父类引用调用重写方法AnimalanimalnewCat(元宝,2);animal.eat();只有通过父类引用调用被重写的方法才能体现运行时多态。3. 多态示例classAnimal{Stringname;intage;publicAnimal(Stringname,intage){this.namename;this.ageage;}publicvoideat(){System.out.println(name吃饭);}}classCatextendsAnimal{publicCat(Stringname,intage){super(name,age);}Overridepublicvoideat(){System.out.println(name吃鱼~~~);}}classDogextendsAnimal{publicDog(Stringname,intage){super(name,age);}Overridepublicvoideat(){System.out.println(name吃骨头~~~);}}publicclassTestAnimal{publicstaticvoideatFood(Animalanimal){animal.eat();}publicstaticvoidmain(String[]args){CatcatnewCat(元宝,2);DogdognewDog(小七,1);eatFood(cat);eatFood(dog);}}运行结果元宝吃鱼~~~ 小七吃骨头~~~代码理解eatFood方法的参数类型是Animal因此它既可以接收Cat对象也可以接收Dog对象。publicstaticvoideatFood(Animalanimal){animal.eat();}在编译阶段编译器只知道animal是Animal类型在运行阶段JVM 会根据animal实际指向的对象类型决定调用哪个类中的eat()方法。这就是动态绑定也是 Java 多态的核心。4. 方法重写4.1 什么是重写方法重写指的是子类对父类中已有的方法进行重新实现。父类提供通用行为子类根据自身特点给出不同实现。classAnimal{publicvoideat(){System.out.println(动物吃饭);}}classCatextendsAnimal{Overridepublicvoideat(){System.out.println(猫吃鱼);}}4.2 方法重写规则方法重写需要注意以下规则方法名必须相同。参数列表必须相同。返回值类型一般相同如果不同必须满足父子类关系。子类方法的访问权限不能比父类方法更严格。private方法不能被重写。static方法不能被重写。final方法不能被重写。构造方法不能被重写。示例classAnimal{publicvoideat(){System.out.println(动物吃饭);}}classDogextendsAnimal{Overridepublicvoideat(){System.out.println(狗吃骨头);}}4.3Override注解重写方法时建议加上Override注解。它可以帮助编译器检查当前方法是否真的构成重写。如果方法名写错、参数列表写错编译器会直接报错。Overridepublicvoideat(){System.out.println(猫吃鱼);}5. 重写和重载的区别对比项重写 Override重载 Overload发生位置父子类之间同一个类中或者父子类中方法名必须相同必须相同参数列表必须相同必须不同返回值类型通常相同或满足父子类关系可以不同但不能只靠返回值区分重载访问权限子类不能更严格没有这个限制多态类型运行时多态编译时多态绑定时机动态绑定静态绑定重点记忆重载看参数重写看父子类关系和方法原型。// 重载方法名相同参数不同publicvoidprint(intx){}publicvoidprint(Strings){}// 重写子类重新实现父类方法Overridepublicvoideat(){}6. 向上转型6.1 什么是向上转型向上转型指的是使用父类引用指向子类对象。语法父类类型 引用名new子类类型();示例AnimalanimalnewCat(元宝,2);animal的编译类型是Animal但实际指向的是Cat对象。6.2 向上转型的三种常见场景场景一直接赋值AnimalanimalnewCat(元宝,2);场景二方法传参publicstaticvoideatFood(Animalanimal){animal.eat();}eatFood(newCat(元宝,2));eatFood(newDog(小七,1));父类类型的参数可以接收不同子类对象代码更加灵活。场景三方法返回值publicstaticAnimalbuyAnimal(Stringtype){if(猫.equals(type)){returnnewCat(猫猫,1);}elseif(狗.equals(type)){returnnewDog(狗狗,1);}returnnull;}方法返回值类型是父类实际返回的可以是任意子类对象。6.3 向上转型的优点向上转型可以让代码更加统一、简单、灵活。例如publicstaticvoideatFood(Animalanimal){animal.eat();}这个方法不用关心传进来的是猫还是狗只要它是Animal的子类就可以调用。6.4 向上转型的限制向上转型后只能调用父类中声明过的方法不能直接调用子类特有的方法。AnimalanimalnewDog(小七,1);animal.eat();// 可以调用因为 Animal 中有 eat 方法// animal.bark(); // 编译失败因为 Animal 中没有 bark 方法7. 向下转型7.1 什么是向下转型向下转型指的是把父类引用重新转换成子类引用。AnimalanimalnewDog(小七,1);Dogdog(Dog)animal;dog.bark();向下转型通常用于调用子类特有方法。7.2 向下转型的风险向下转型不安全。如果父类引用实际指向的对象不是目标子类类型运行时会抛出ClassCastException。AnimalanimalnewDog(小七,1);Catcat(Cat)animal;// 运行时报错原因是animal实际指向的是Dog对象不能强制转换成Cat。7.3 使用instanceof提高安全性向下转型前建议使用instanceof判断对象真实类型。AnimalanimalnewDog(小七,1);if(animalinstanceofDog){Dogdog(Dog)animal;dog.bark();}if(animalinstanceofCat){Catcat(Cat)animal;cat.mew();}这样可以避免错误转换导致程序崩溃。8. 动态绑定和静态绑定8.1 静态绑定静态绑定也叫前期绑定指的是在编译阶段就能确定具体调用哪个方法。典型例子方法重载。publicvoidprint(intx){}publicvoidprint(Strings){}编译器根据传入参数类型决定调用哪个重载方法。8.2 动态绑定动态绑定也叫后期绑定指的是编译阶段不能确定具体调用哪个方法需要等程序运行时根据对象真实类型决定。典型例子方法重写。AnimalanimalnewCat(元宝,2);animal.eat();// 运行时调用 Cat 的 eat 方法动态绑定是多态能够实现的关键。9. 多态的好处9.1 降低代码复杂度不使用多态时可能需要大量if-else判断对象类型if(shape.equals(cycle)){cycle.draw();}elseif(shape.equals(rect)){rect.draw();}elseif(shape.equals(flower)){flower.draw();}使用多态后可以把不同对象统一放到父类数组中Shape[]shapes{newCycle(),newRect(),newCycle(),newRect(),newFlower()};for(Shapeshape:shapes){shape.draw();}调用者只需要调用draw()具体画什么由对象本身决定。9.2 提高代码扩展性如果新增一个图形类只需要继承Shape并重写draw()方法。classTriangleextendsShape{Overridepublicvoiddraw(){System.out.println(△);}}原来的调用逻辑基本不用修改扩展成本更低。9.3 让代码更符合面向对象思想多态让程序更关注“对象能做什么”而不是“对象具体是什么类型”。例如shape.draw();这行代码表达的是“让图形自己画出来”而不是由调用者判断它到底是圆形、矩形还是三角形。10. 多态的缺点和限制10.1 运行效率可能略低多态需要在运行时确定具体调用哪个方法相比编译阶段直接确定的方法调用效率可能略低。不过在大多数实际开发中这点性能差异通常不是主要问题代码的可维护性和可扩展性更重要。10.2 属性没有多态性Java 中的多态主要针对方法不针对属性。当父类和子类中存在同名属性时通过父类引用访问属性访问的是父类中的属性。classAnimal{publicStringnameAnimal;}classCatextendsAnimal{publicStringnameCat;}publicclassTest{publicstaticvoidmain(String[]args){AnimalanimalnewCat();System.out.println(animal.name);// Animal}}注意属性访问看引用类型方法调用看对象真实类型。10.3 构造方法没有多态性构造方法不能被继承也不能被重写因此构造方法不存在多态。11. 避免在构造方法中调用可被重写的方法在构造方法中调用可被子类重写的方法可能会产生隐藏问题。示例classB{publicB(){func();}publicvoidfunc(){System.out.println(B.func());}}classDextendsB{privateintnum1;Overridepublicvoidfunc(){System.out.println(D.func() num);}}publicclassTest{publicstaticvoidmain(String[]args){DdnewD();}}运行结果D.func() 0原因分析创建D对象时会先调用父类B的构造方法。父类构造方法中调用了func()由于动态绑定会调用子类D重写后的func()。但是此时子类对象还没有初始化完成num还没有被赋值为1所以打印的是默认值0。结论构造方法中尽量不要调用普通实例方法尤其是可能被子类重写的方法。可以调用的方法通常是private方法因为不能被重写。final方法因为不能被重写。简单、稳定、不依赖子类状态的方法。12. 多态常见易错点易错点一父类引用不能调用子类特有方法AnimalanimalnewDog(小七,1);// animal.bark(); // 编译失败解决方式先向下转型再调用。if(animalinstanceofDog){Dogdog(Dog)animal;dog.bark();}易错点二向下转型可能运行时报错AnimalanimalnewDog(小七,1);Catcat(Cat)animal;// ClassCastException转换前要先判断if(animalinstanceofCat){Catcat(Cat)animal;cat.mew();}易错点三属性没有多态AnimalanimalnewCat();System.out.println(animal.name);访问哪个属性取决于引用变量的类型而不是对象真实类型。易错点四private方法不能被重写classAnimal{privatevoideat(){}}子类中即使写了同名方法也不是重写。易错点五static方法不能被重写静态方法属于类不属于对象因此不参与运行时多态。易错点六final方法不能被重写classAnimal{publicfinalvoideat(){}}子类不能重写final修饰的方法。13. 多态记忆口诀继承是前提重写是核心父类引用是入口。 编译看左边运行看右边。 属性看左边方法看右边。 向上转型自动完成向下转型需要谨慎。 转型之前 instanceof避免异常更安全。解释编译看左边变量声明的类型决定能调用哪些成员。运行看右边对象真实类型决定重写方法的执行结果。属性看左边属性没有多态访问属性看引用类型。方法看右边被重写的方法具有多态调用结果看对象真实类型。14. 学习重点总结多态是同一个行为在不同对象上产生不同结果。多态的三个条件继承、重写、父类引用调用重写方法。方法重写发生在父子类之间方法重载主要看参数列表。向上转型可以让代码更灵活但不能调用子类特有方法。向下转型可以调用子类特有方法但存在类型转换风险。使用instanceof可以提高向下转型的安全性。多态可以降低代码复杂度提高扩展性。属性和构造方法不具备多态性。构造方法中尽量不要调用可能被子类重写的方法。多态的核心机制是动态绑定。