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

Java学习笔记:多态

对多态的理解
多态字面意思是“多种形态”。同一个方法调用,实际执行的效果不一样。
父类类型的变量,指向子类对象,调用方法时执行子类的重写版本。

多态需要三个条件:

继承关系

方法重写

父类引用指向子类对象

多态的两种形式

  1. 向上转型(自动)
    父类引用指向子类对象。这样写是自动的,不需要强制转换。

java
Animal animal = new Dog();
这时候animal只能调用父类中有的方法,不能调用子类特有的方法。但调用被重写的方法时,执行的是子类的版本。

  1. 向下转型(强制)
    把父类引用转回子类类型。需要强制转换,而且有风险。

java
Dog dog = (Dog) animal;
向下转型前最好用instanceof判断一下,不然转错类型会报ClassCastException。

代码示例
java
public class Animal {
protected String name;

public Animal(String name) {
this.name = name;
}

public void makeSound() {
System.out.println("动物发出声音");
}

public void eat() {
System.out.println(name + "在吃东西");
}

public void sleep() {
System.out.println(name + "在睡觉");
}
}

public class Dog extends Animal {
private String breed;

public Dog(String name, String breed) {
super(name);
this.breed = breed;
}

@Override
public void makeSound() {
System.out.println(name + "汪汪叫");
}

@Override
public void eat() {
System.out.println(name + "在吃狗粮");
}

public void wagTail() {
System.out.println(name + "摇尾巴");
}

public void fetch() {
System.out.println(name + "叼回了飞盘");
}
}

public class Cat extends Animal {
private String color;

public Cat(String name, String color) {
super(name);
this.color = color;
}

@Override
public void makeSound() {
System.out.println(name + "喵喵叫");
}

@Override
public void eat() {
System.out.println(name + "在吃鱼");
}

@Override
public void sleep() {
System.out.println(name + "缩成一团睡觉");
}

public void climb() {
System.out.println(name + "爬上了树");
}
}

public class Bird extends Animal {
private double wingSpan;

public Bird(String name, double wingSpan) {
super(name);
this.wingSpan = wingSpan;
}

@Override
public void makeSound() {
System.out.println(name + "叽叽喳喳");
}

@Override
public void eat() {
System.out.println(name + "在吃虫子");
}

public void fly() {
System.out.println(name + "飞起来了");
}
}

public class TestPolymorphism {
public static void main(String[] args) {
System.out.println("=== 基本多态演示 ===\n");

Animal a1 = new Dog("旺财", "金毛");
Animal a2 = new Cat("咪咪", "白色");
Animal a3 = new Bird("小飞", 0.5);

a1.makeSound();
a2.makeSound();
a3.makeSound();

a1.eat();
a2.eat();
a3.eat();

System.out.println("\n=== 同一个数组统一处理 ===\n");

Animal[] animals = new Animal[4];
animals[0] = new Dog("小黑", "德牧");
animals[1] = new Cat("花花", "橘色");
animals[2] = new Bird("啾啾", 0.3);
animals[3] = new Dog("大黄", "中华田园犬");

for (Animal animal : animals) {
animal.makeSound();
animal.eat();
animal.sleep();
System.out.println("---");
}

System.out.println("\n=== 向下转型和instanceof ===\n");

Animal unknown = new Dog("来福", "拉布拉多");

if (unknown instanceof Dog) {
Dog d = (Dog) unknown;
d.wagTail();
d.fetch();
}

if (unknown instanceof Cat) {
Cat c = (Cat) unknown;
c.climb();
} else {
System.out.println("来福不是猫,不能调用爬树方法");
}

System.out.println("\n=== 遍历时调用子类特有方法 ===\n");

for (Animal animal : animals) {
if (animal instanceof Dog) {
Dog d = (Dog) animal;
d.wagTail();
} else if (animal instanceof Cat) {
Cat c = (Cat) animal;
c.climb();
} else if (animal instanceof Bird) {
Bird b = (Bird) animal;
b.fly();
}
}

System.out.println("\n=== 多态参数 ===\n");

feedAnimal(a1);
feedAnimal(a2);
feedAnimal(a3);

System.out.println("\n=== 多态返回值 ===\n");

Animal created = createAnimal(1);
created.makeSound();

Animal created2 = createAnimal(2);
created2.makeSound();
}

public static void feedAnimal(Animal animal) {
System.out.print("喂食:");
animal.eat();
}

public static Animal createAnimal(int type) {
if (type == 1) {
return new Dog("新来的狗", "柯基");
} else if (type == 2) {
return new Cat("新来的猫", "黑");
} else {
return new Bird("新来的鸟", 0.4);
}
}
}
今天踩的坑
我写的错误 为什么错 应该怎么写
用父类引用调用子类特有方法 编译时不通过 先向下转型再调用
向下转型不检查instanceof 转错类型会崩溃 转型前用instanceof判断
以为多态对属性也生效 属性没有多态,看声明类型 方法才有多态,属性用getter
把子类对象赋值给父类后忘了本来是什么类型 转型错误 记录类型或用instanceof
在循环里频繁instanceof 代码丑效率低 考虑把方法提取到父类

多态的优缺点
优点:

代码更通用,可以用父类类型写一次逻辑处理所有子类

降低耦合,调用方只依赖父类不依赖具体子类

符合开闭原则,新增子类不需要改现有代码

让代码更简洁,不用写一堆if-else判断类型

缺点:

不能直接调用子类特有的方法

代码阅读起来需要看具体实现才知道执行哪个版本

向下转型有风险

性能上比直接调用稍微慢一点(要动态绑定)

多态中的注意事项
属性没有多态:用父类引用访问属性,拿到的是父类的属性值,不是子类的

静态方法没有多态:静态方法属于类,调用时看引用类型不看对象类型

private方法没有多态:private不能被重写,不存在多态

final方法没有多态:final不能被重写

构造器没有多态

instanceof的使用场景
向下转型前的安全检查

需要调用子类特有方法时

对集合中的元素进行分类处理

java
if (obj instanceof String) {
String s = (String) obj;
}
Java 16之后可以用模式匹配:

java
if (obj instanceof String s) {
System.out.println(s.length());
}
多态参数和多态返回值
多态参数:方法参数写成父类类型,调用时可以传入任何子类对象。这是多态最常用的场景。

多态返回值:方法返回父类类型,实际可以返回任何子类对象。工厂模式常用这种写法。

和重写的关系
多态和重写是绑定的。没有重写就没有多态。多态依赖重写来产生不同的行为。

总结
多态让父类变量指向子类对象,同一个方法调用产生不同效果。核心价值是用统一的代码处理不同类型的数据。加上instanceof做安全检查,向下转型调用子类特有功能。写代码时优先用父类类型声明,需要特殊处理再转型。

http://www.rkmt.cn/news/1372356.html

相关文章:

  • ChatGPT记忆功能安全风险预警,3大数据泄露漏洞已验证(附GDPR/等保2.0合规配置清单)
  • C++的STL
  • DLSS Swapper深度解析:如何实现跨平台游戏DLSS版本智能管理
  • 【优化调度】基于改进遗传算法求解带时间窗约束多卫星任务规划附Matlab代码
  • 2026年5月有实力的一体化污水提升泵站/一体化泵站厂家推荐河北铄康环保设备有限公司,水质适应性广各类浑浊污水均可稳定输送处理 - 品牌鉴赏师
  • 溧阳沙发翻新换皮换布面靠谱商家优选推荐|匠阁沙发翻新、御匠沙发翻新、锦修沙发翻新三大品牌、全品类沙发翻新换皮换布一站式服务 - 卓信营销
  • 建立在不同的基线模型上,GAT,GCN,和GIN
  • 2026年5月优秀的EPS外墙装饰/EPS装饰线条厂家推荐丰县建鑫泡沫制品有限公司,雕花构件定制打造建筑独特标识 - 品牌鉴赏师
  • 2026长岛民宿排名指南,长岛海东渔家民宿没白来! - 资讯纵览
  • 英语 听力 重读软件app
  • AI写作辅助平台8款AI写作辅助软件梯队榜,毕业护航!
  • 权威测评!2026年顶尖AI论文写作软件榜单,高质初稿轻松写
  • 2026 北京包包回收实测:上门回收估价 vs 线下实体店,哪个更划算 - 奢侈品回收测评
  • 如何利用AI工具变现:一个老程序员的真实观察
  • Claude在国内用不了?我挨个试了一遍
  • 纯视觉破界空间感知 自研体系领跑视频孪生领域
  • Tableau Server安全加固与合规运维实战指南
  • CVE-2017-17215实战复现:华为HG532路由器栈溢出漏洞深度解析
  • 2026年5月有实力的电磁阀厂家推荐钢特阀门科技有限公司,优化产品结构提升流体调控效能 - 品牌鉴赏师
  • 专业级GPU内存检测:MemTestCL的5个实战场景深度解析
  • Windows下JMeter高并发压测端口耗尽问题排查与修复
  • 【Java EE】IPv6
  • 因果推断与双机器学习在LED制造返工决策中的实战应用
  • 2026年5月诚信的气动元器件/气动附件厂家推荐钢特阀门科技有限公司,恪守经营本心打造靠谱气动配套产品 - 品牌鉴赏师
  • 2026广州除四害公司推荐榜:服务口碑排名谁更强 - 资讯纵览
  • 教育机构搭建AI编程实验室如何借助Taotoken管控学生用量与成本
  • 夏季前挡膜怎么选?固驰蓝闪幻蝶车窗膜给出不止隔热的答案
  • 沁源矿难警示:摆脱佩戴依赖,构建可靠井下人员定位体系
  • 李飞飞团队新作ESI-Bench:具身智能的ImageNet来了!
  • 卖瓦楞纸箱怎么找客户?下游工厂在哪里