当前位置: 首页 > news >正文

JavaSE-多态

多态的概念

        在完成某个行为时,不同的对象在完成时会呈现出不同的状态。

比如:动物都会吃饭,而猫和狗都是动物,猫在完成吃饭行为时吃猫粮,狗在完成吃饭行为时吃狗粮,猫和狗都会叫,狗在完成这个行为时会狗叫,而哈基米会哈气。

在编程中,多态是指利用子类继承父类的特性在使用对象时达到简化代码的目的。

多态的实现条件

在java中要实现多态,必须要满足如下几个条件,缺一不可:
1. 必须在继承体系下
2. 子类必须要对父类中方法进行重写
3. 通过父类的引用调用重写的方法
多态体现:在代码运行时,当传递不同类对象时,会调用对应类中的方法。

下面是简单的示例:

public class Animal {public String name;public int age;public Animal(String name,int age) {this.name = name;this.age = age;}public void cry(){System.out.println(name+"正在叫---");}}public class Dog extends Animal{public Dog(String name,int age){super(name,age);}public void cry(){System.out.println(name+"正在狗叫---");}
}ublic class Cat extends Animal{public Cat(String name,int age){super(name,age);}public void cry(){System.out.println(name+"正在哈气---");}
}public class test {public static void main(String[] args) {Animal dog = new Dog("富贵",3);Animal cat = new Cat("哈吉米",4);dog.cry();cat.cry();}
}

运行结果:

在父类Animal和子类Dog与Cat中都有名为cry的方法,我们可以发现在主方法实例化子类后调用的cry均为子类本身的方法,这种现象就称之为多态。 

重写

重写(override):也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变。即外壳不变,核心重写!重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

【方法重写的规则】
1.子类在重写父类的方法时,一般必须与父类方法原型一致: 返回值类型 方法名 (参数列表) 要完全一致
2.被重写的方法返回值类型可以不同,但是必须是具有父子关系的
3.访问权限不能比父类中被重写的方法的访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected
4.父类被static、private修饰的方法、构造方法都不能被重写。
5.重写的方法, 在编译器中使用 @Override 注解来显式指定. 有了这个注解能帮我们进行一些合法性校验. 例如不小心将方法名字拼写错了 (比如写成 aet), 那么此时编译器就会发现父类中没有 aet 方法, 就会编译报错, 提示无法构成重写。

方法的重写与重载的区别:

在重写中,两个方法的参数列表必须相同,返回类型必须相同或者构成父子关系,访问权限限定符必须相同或者更宽松,而在重载中,参数列表必须不同才能构成重载,返回类型可以随意修改,访问权限限定符可以随意修改。 

静态绑定:也称为前期绑定(早绑定),即在编译时,根据用户所传递实参类型就确定了具体调用那个方法。典型代表函数重载。
动态绑定:也称为后期绑定(晚绑定),即在编译时,不能确定方法的行为,需要等到程序运行时,才能够确定具体调用那个类的方法,典型代表函数重写。

两种转型

向上转型

概念;创建一个子类对象,将其作为父类对象来使用。

语法格式:父类类型 对象名 = new 子类类型();

 

由于父类包含子类,父类是大范围,子类是小范围,所以这种转型就是一种父类对子类的引用。

 向上转型的使用场景:

1.直接赋值

Animal dog = new Dog("富贵",3);

将子类直接赋值给父类。 

2.方法传参

public void AnimalCry(Animal a){a.cry();}

在方法的参数列表中使用父类Animal声明,在传参时就可以传入子类Cat和Dog。 

3.方法返回值

public Animal buyAnimal(int a){if(a==1){return new Cat("猫猫",1);}else if(a==2){return new Dog("狗狗",1);}else{return null;}}

示例:

public class test {public static void animalCry(Animal a){a.cry();}public static Animal buyAnimal(int a){if(a==1){return new Cat("猫猫",1);}else if(a==2){return new Dog("狗狗",1);}else{return null;}}public static void main(String[] args) {Animal dog = new Dog("富贵",3);Animal cat = new Cat("哈吉米",4);animalCry(dog);animalCry(cat);Animal sweet = buyAnimal(1);sweet.cry();sweet = buyAnimal(2);sweet.cry();}
}

在主方法中,我们首先实例化Dog和Cat,然后将两个子类对象传参给animalCry,然后用sweet接受buyAnimal返回的子类对象。这里就使用到了三种向上转型的场景。

向上转型的优点:使代码更加方便简洁。

向上转型的缺点:不能使用子类特有的方法。

向下转型

将一个子类对象向上转型为父类对象后,无法在使用子类特有的方法,此时需要用到向下转型。

public class Animal {public String name;public int age;public Animal(String name,int age) {this.name = name;this.age = age;}public void cry(){System.out.println(name+"正在叫---");}}public class Dog extends Animal{public Dog(String name,int age){super(name,age);}public void cry(){System.out.println(name+"正在狗叫---");}public void eatBone(){System.out.println(name+"正在啃骨头---");}
}public class Cat extends Animal{public Cat(String name,int age){super(name,age);}public void cry(){System.out.println(name+"正在哈气---");}public void eatFish(){System.out.println(name+"正在吃鱼---");}
}public class test {public static void main(String[] args) {Dog dog = new Dog("富贵",3);Cat cat = new Cat("哈吉米",4);//向上转型Animal animal =cat;animal.cry();animal=dog;animal.cry();animal.eatBone();//这里编译器会将animal作为Animal对象处理//而Animal类中没有eatBone方法//所以会编译报错cat = (Cat)animal;cat.eatFish();//这里对animal进行强制类型转换为cat//但是animal在向上转换之前指向的实际是dog//所以这里在运行时会出现异常dog=(Dog)animal;dog.eatBone();}
}

删除错误代码后的运行结果:

为了确保向下转型时的安全性,Java引入了instanceof关键字

当(a instanceof b )为真时,代表a为b类实例化的对象,以此判断a的类型。 

多态的优缺点

优点

假设有如下父类和子类:

class Shape {public void draw() {System.out.println("画图形!");}}
class Rect extends Shape{public void draw() {System.out.println("♦");}
}
class Cycle extends Shape{public void draw() {System.out.println("●");}
}
class Flower extends Shape{public void draw() {System.out.println("❀");}
}

如果我们不使用多态思想,那么需要这样打印这些图形:

public static void drawShapes() {Rect rect = new Rect();Cycle cycle = new Cycle();Flower flower = new Flower();String[] shapes = {"cycle", "rect", "cycle", "rect", "flower"};for (String shape : shapes) {if (shape.equals("cycle")) {cycle.draw();} else if (shape.equals("rect")) {rect.draw();} else if (shape.equals("flower")) {flower.draw();}}}

使用多态思想:

public static void drawShapes() {// 我们创建了一个 Shape 对象的数组.Shape[] shapes = {new Cycle(), new Rect(), new Cycle(), new Rect(), new Flower()};for (Shape shape : shapes) {shape.draw();}}

两种方法输出相同,代码量却相去甚远:

我们可以看出多态思想为我们省去了许多if-else分支,降低了代码的圈复杂度 ,这就是多态的第一个优点。

多态的第二个优点时可扩展性强,如果新增一种形状,使用多态的方法改动也更加简洁:

class Triangle extends Shape {public void draw() {System.out.println("△");}
}

缺点

1. 属性没有多态性
当父类和子类都有同名属性的时候,通过父类引用,只能引用父类自己的成员属性
2. 构造方法没有多态性

http://www.dtcms.com/a/278235.html

相关文章:

  • 2023.05.06 更新前端面试问题总结(12道题)
  • 如何将FPGA设计的验证效率提升1000倍以上(4)
  • Flink数据流高效写入MySQL实战
  • 大模型微调(一):基于Swift框架进行自我认知微调(使用Lora微调Qwen3-8B模型)
  • 芯片相关必备
  • 初识drag2框架,drag2注入的基本原理
  • [Python 基础课程]元组
  • HashMap 和 ConcurrentHashMap 的区别
  • JAVA学习笔记 JAVA开发环境部署-001
  • 【Datawhale夏令营】用AI做带货视频评论分析
  • Origin自带的悬浮尺子,Screen Ruler的最佳平替
  • C# 接口(接口可以继承接口)
  • 终极剖析HashMap:数据结构、哈希冲突与解决方案全解
  • 【面板数据】上市公司诉讼风险、诉讼次数等数据集(2007-2023年)
  • 【LeetCode100】--- 4.移动零【复习回顾】
  • 剑指offer58_和为S的连续正数序列
  • 深入理解 LangChain:AI 应用开发的全新范式
  • 人工智能到底是什么?揭开 AI 的神秘面纱
  • Spring @Autowired:依赖注入的核心奥秘
  • markdown-it-mathjax3-pro —— 新一代 Markdown 数学公式渲染插件
  • 代码精进之路
  • NumPy 中 np.c_ 的用法解析
  • Prometheus 第一篇:快速上手
  • 哪些行业的“反内卷”前景更好?
  • DL00454-深度学习牲畜资产管理圈养生猪行为识别含数据集
  • Docker搭建Redis哨兵集群
  • 代码部落 20250713 CSP-S复赛 模拟赛
  • Windows上使用配置Claude Code教程
  • 软件文档体系深度解析:工程视角下的文档架构与治理
  • 知识图谱构建简单分享