当前位置: 首页 > 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.jsqmd.com/news/879934/

相关文章:

  • 2026北京GEO优化公司综合测评:技术实力、服务能力与选型核心指标对比 - GEO优化
  • 2026年4月知名的滚筒输送线公司推荐,倍速链线/防静电工作台/流水线工作台/皮带输送线,滚筒输送线供应商哪家好 - 品牌推荐师
  • Go语言模块化单体架构实战指南:从设计到落地的完整解析
  • C++的STL
  • 日志留存不合规?审计追溯难定位?DeepSeek 3.2+审计日志的4层加密+时间戳锚定机制,立即规避等保2.0扣分风险
  • Grafana 操作进阶:生产级平滑升级与数据备份
  • 岩石识别与展示系统设计文档
  • 踩坑无数!终于捋顺Git基础核心工作流(新手必看)
  • 如何用NightX Client打造终极Minecraft 1.8.9体验?完整功能解析+新手教程 [特殊字符]
  • 卖轴承怎么找客户?下游工厂在哪里
  • 用过才敢说!2026年最值得信赖的专业AI论文网站
  • Tableau Server安全加固与合规运维实战指南
  • 保姆级教程:在Ubuntu 22.04上搞定rMATS 4.1.2安装,附赠conda环境配置与常见报错解决
  • 如何在Mac上免费运行Windows游戏与应用:Whisky完整指南
  • Java小练
  • 权威测评!2026年顶尖AI论文写作软件榜单,高质初稿轻松写
  • CVE-2017-17215实战复现:华为HG532路由器栈溢出漏洞深度解析
  • 2026年5月知名的仿真人造草坪/硅pu篮球场厂家推荐灵动运体(河南)体育科技有限公司 - 品牌鉴赏师
  • 保姆级教程:用向日葵远程在Windows系统上安装Vector CANape 21.0.10(附Demo工程位置详解)
  • 6款主流降AIGC网站 创作效率拉满
  • AI写作辅助平台8款AI写作辅助软件梯队榜,毕业护航!
  • ClamAV更新失败真相:DNS TXT协议与版本兼容性解析
  • 邳州沙发翻新换皮换布面靠谱商家优选推荐|匠阁沙发翻新、御匠沙发翻新、锦修沙发翻新三大品牌、全品类沙发翻新换皮换布一站式服务 - 卓信营销
  • 溧阳沙发翻新换皮换布面靠谱商家优选推荐|匠阁沙发翻新、御匠沙发翻新、锦修沙发翻新三大品牌、全品类沙发翻新换皮换布一站式服务 - 卓信营销
  • 2026年5月有实力的一体化污水提升泵站/一体化泵站厂家推荐河北铄康环保设备有限公司,水质适应性广各类浑浊污水均可稳定输送处理 - 品牌鉴赏师
  • 建立在不同的基线模型上,GAT,GCN,和GIN
  • 2026年5月优秀的EPS外墙装饰/EPS装饰线条厂家推荐丰县建鑫泡沫制品有限公司,雕花构件定制打造建筑独特标识 - 品牌鉴赏师
  • ComfyUI-Impact-Pack V8进阶实战:掌握AI图像智能修复的3大核心场景与性能优化
  • 视觉无感定位破局 孪生技术重构空间管控逻辑
  • 前景理论(Prospect Theory)深入解析