JavaSE--方法覆盖和多态
一、方法覆盖Override
1、什么时候使用Override
例如:以下代码:鸟儿在执行move方法时,最好输出“鸟儿在飞翔”,但是当前程序在执行move方法时,输出“动物在移动”,显然Bird子类继承来的方法无法满足需求
子类继承父类之后,当继承过来的方法无法满足当前子类的业务需求时,子类有权利进行重新编写方法
public class OverrideTest{ public static void main(String[] args){ Bird b = new Bird(); b.move(); Cat c = new Cat(); c.move(); } } // 父类 class Animal{ public void move(){ System.out.println("动物在移动"); } // protected表示受保护的,没有public开放 protected void eat(){ System.out.println("动物在吃"); } } // 子类 class Bird extends Animal{ // 子类继承父类之后,有一些行为可能需要进行改进 // move重写 public void move(){ System.out.println("鸟儿在飞翔"); } /* 错误:正在城市分配更低的访问权限,以前为public protected void move(){ System.out.println("鸟儿在飞翔"); } */ // 可以更高 public void eat(){ System.out.println("鸟儿在抓虫子吃"); } public void sing(){ System.out.println("鸟儿在唱歌"); } } class Cat extends Animal{ public void move(){ System.out.println("猫猫在走路"); } public void catchMouse(){ System.out.println("猫猫抓老鼠"); } }
2、结论
当子类对父类继承过来的方法进行“方法覆盖”之后,子类对象调用该方法的时候,一定执行覆盖之后的方法
3、构成方法覆盖的条件
条件1:两个类必须有继承关系
条件2:重写之后的方法和之前的方法具有:相同的方法名、相同的形参列表、相同的返回值类型
注意:相同的返回值类型:对于返回值类型是基本数据类型,必须一致
对于返回值类型是引用数据类型,可以变小,但意义不大,不会这样写
条件3:访问权限不能更低,可以更高
条件4:重写之后的方法不能比之前的方法抛出更多的异常,可以更少
注意事项:注意1:方法覆盖只是针对于方法,和属性无关
注意2:私有方法无法覆盖
注意3:构造方法不能被继承,所以构造方法也不能被覆盖
注意4:方法覆盖只是针对于实例方法,静态方法覆盖没有意义
4、解释:方法覆盖只是针对于实例方法,静态方法覆盖没有意义
方法覆盖只针对实例方法,静态方法覆盖没有意义
/* 1、 没有多态机制,方法覆盖可有可无 没有多态机制,方法覆盖也可以没有,如果无法满足子类业务需求时,子类完全可以重新定义一个新方法 2、静态方法存在方法覆盖么? 多态自然和对象有关系 但是静态一般和对象没有关系 所以一般情况下,我们会说“静态方法”没有方法覆盖 */ public class OverrideTest05{ public static void main(String[] args){ Animal a = new Cat(); a.doSome();// 输出:Animal的doSome方法 Animal.doSome(); Cat.doSome(); } } class Animal{ public static void doSome(){ System.out.println("Animal的doSome方法"); } } class Cat extends Animal{ // 尝试覆盖 public static void doSome(){ System.out.println("Cat的doSome方法"); } }
5、解释:私有方法无法覆盖
在外部类无法访问私有的
二、多态
1、向上转型与向下转型
1)向上转型
子----->父(可以这样叫自动类型转换)
2)向下转型
父----->子(可以这样叫强制类型转换,需要加强制类型转换符)
因为自动类型转换和强制类型转换是基本数据类型之间,向上转型和向上转型是在引用类型之间
注意:java中允许向上转型也允许向下转型,但是无论哪种,两种类型之间必须有继承关系,没有继承关系编译器会报错
2、什么时候使用向下转型
不要随便使用强制类型转换
当你需要访问的是子类对象中“特有”的方法,此时需要向下转型
3、多态的基础语法
父类型引用指向子类型对象
包括编译阶段和运行阶段。编译阶段:绑定父类方法;运行阶段:动态绑定子类方法
public class Test01{ public static void main(String[] args){ Animal a1 = new Animal(); a1.move(); Cat c = new Cat(); c.move(); Bird b = new Bird(); b.move(); /* 父类型的引用允许指向子类型的对象 允许a2这个父类型引用指向子类型的对象 */ Animal a2 = new Cat(); Animal a3 = new Bird(); /* 什么是多态 分析a2.move(); java程序分为编译阶段和运行阶段 编译阶段: 编译器只知道a2的类型是Animal,所以编译器在检查语法的时候会去Animal.class字节码文件中找move方法 找到之后,绑定上move方法,编译通过,静态绑定成功(编译阶段属于静态绑定) 运行阶段: 实际上在堆内存中创建的java对象是Cat对象,所以在move时,真正参与move的对象是Cat, 所以运行阶段会动态执行Cat对象的move方法,这个过程属于运行阶段绑定(运行阶段绑定属于动态绑定) 多态表示多种形态: 编译的时候时一种形态,运行的时候是一种形态 */ a2.move();// 猫猫在走路 a3.move();// 鸟儿在飞翔 Animal a5 = new Cat(); // 分析程序一定要分析静态绑定和动态绑定 // 编译不能通过,报错,编译器只知道a5是Animal类型,去Animal.class中找catchMouse没找到 // a5.catchMouse(); // 如果a5非要使用catchMouse方法,就需要使用向下转型 // 什么时候使用向下转型:这个行为是子类型对象特有的方法 Cat x = (Cat)a5;// 强制转换为Cat类型 x.catchMouse(); } }
4、向下转型有风险,怎样避免
/* 编译不会报错 但是运行报错 因为在运行阶段,堆内存中实际存放的Bird对象,但是又强制转成Cat,Bird与Cat没有继承关系 */ Animal a6 = new Bird(); Cat y = (Cat)a6; y.catchMouse();
1)避免向下转型风险
Java规范中要求:任何时候对类型进行向下转型时,一定要先使用instanceof运算符进行判断
// 怎样避免ClassCastException异常 类转换异常发生 /* 运算符 instanceof 第一:instanceof可以在运行阶段动态判断引用指向的对象的类型 第二:instanceof语法 (引用 instanceof 类型) 第三:instanceof运算符的运算结果只能是true、false 第四:c是一个引用,c变量保存了内存地址指向了堆中的对象 假设(c instanceof Cat)为true表示:c引用指向的堆内存中的java对象是一个Cat 假设(c instanceof Cat)为true表示:c引用指向的堆内存中的java对象不是是一个Cat */ Animal a6 = new Bird(); if (a6 instanceof Cat){// 如果a6是Cat,在强制类型转换 Cat y = (Cat)a6; y.catchMouse(); }
2)为什么要用instanceof判断
/* 明明可以看到new的是谁,为什么还要判断呢 原因是:有可能以后肉眼看不到 */ Animal x = new Bird(); Animal y = new Cat(); if(x instanceof Bird){ Bird b = (Bird)x; b.sing(); }else if(x instanceof Cat){ Cat c = (Cat)x; c.catchMouse(); } if(y instanceof Bird){ Bird b = (Bird)y; b.sing(); }else if(y instanceof Cat){ Cat c = (Cat)y; }
class AnimalTest{ public void test(Animal a){ // 别人调用时调用test方法时传参数是穿一个Bird还是Cat // 别人不知道要传过来一个什么 // Cat c = (Cat)a; // c.catchMouse(); if(x instanceof Bird){ Bird b = (Bird)a; b.sing(); }else if(x instanceof Cat){ Cat c = (Cat)a; c.catchMouse(); } } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 【杭电多校比赛记录】2025“钉耙编程”中国大学生算法设计春季联赛(1)