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

JAVA多态——向上转型

之前在写多态的博客时,向上转型方面的知识点没有总结。

首先再总结一下多态。

多态

多态是面向对象编程中的一个重要概念,允许不同类的对象对同一消息做出不同的响应。多态性主要通过继承和接口实现,使得代码更加灵活和可扩展。

多态的实现方式

方法重载(Overloading)
方法重载是指在同一个类中定义多个同名方法,但这些方法的参数列表不同(参数类型、数量或顺序不同)。编译器根据调用时传递的参数来决定调用哪个方法。

class Calculator {int add(int a, int b) {return a + b;}double add(double a, double b) {return a + b;}
}

方法重写(Overriding)
方法重写是指子类重新定义父类中已有的方法。子类对象调用该方法时,会执行子类中的实现,而不是父类中的实现。

class Animal {void sound() {System.out.println("Animal makes a sound");}
}class Dog extends Animal {void sound() {System.out.println("Dog barks");}
}

接口实现
接口定义了一组方法签名,不同的类可以实现同一个接口,并提供不同的实现。通过接口引用调用方法时,实际执行的是具体实现类中的方法。

interface Shape {void draw();
}class Circle implements Shape {public void draw() {System.out.println("Drawing a circle");}
}class Square implements Shape {public void draw() {System.out.println("Drawing a square");}
}

多态的优势

代码复用
通过继承和接口,可以减少代码重复,提高代码的可维护性。

扩展性
新增类时,无需修改现有代码,只需实现相应的接口或继承父类即可。

灵活性
多态允许程序在运行时根据对象的实际类型调用相应的方法,增强了程序的灵活性。

多态的应用场景

框架设计
在框架设计中,多态性允许开发者通过实现特定接口或继承特定类来扩展框架功能。

插件系统
插件系统通常利用多态性,允许开发者通过实现特定接口来添加新功能。

事件处理
在事件驱动编程中,多态性允许不同的事件处理器对同一事件做出不同的响应。

多态性是面向对象编程的核心特性之一,合理使用多态可以显著提高代码的质量和可维护性。

向上转型(Upcasting)是面向对象编程中的一个概念,指的是将子类对象赋值给父类引用。这种转型是自动进行的,不需要显式地进行类型转换。向上转型的主要目的是实现多态性,允许父类引用调用子类对象的方法。

向上转型:

定义

将子类对象赋值给父类引用的过程,称为向上转型。

  • 语法父类类型 引用变量 = new 子类类型();
  • 本质:子类对象被视为父类类型,是一种隐式转换,无需显式声明。

向上转型的特点

向上转型是安全的,因为子类对象包含了父类的所有属性和方法。通过父类引用,可以访问子类对象中继承自父类的方法和属性,但不能直接访问子类特有的方法和属性。

向上转型的示例

以下是一个简单的Java示例,展示了向上转型的使用:

package com.qcby;public class A {public String name;public int age;public void run(){System.out.println("A跑的很快");}public void eat(String name){System.out.println(name+ "吃的很多");}
}
--------------------------------------------
package com.qcby;public class B extends A{public String sex;public double height;public void fly(){System.out.println("B飞得很高");}public void run(){System.out.println("B跑的很快");}
}-----------------------------------------
package com.qcby;public class Test {public static void main(String[] args) {A ab = new B();ab.name = "张三";ab.age = 18;ab.run();ab.eat("张三");}
}
-------------------------------------------
//运行结果:
//B跑的很快
//张三吃的很多

在这个示例中,,A ab = new B(); 这行代码正是向上转型(Upcasting)的典型体现。

public class Test {public static void main(String[] args) {A ab = new B();  // 向上转型ab.name = "张三";ab.age = 18;ab.run();      // 调用B类的run()ab.eat("张三");  // 调用A类的eat()}
}
  •  隐式转换new B() 是子类对象,自动转换为父类 A 类型。
  • 编译期检查:编译器只允许调用父类 A 中定义的方法和属性。
  • 运行期行为:重写的方法会根据实际对象类型(B)动态调用。

向上转型的特性

变量的类型是父类类型,因此只能访问父类中定义的方法和属性。子类特有的方法和属性在向上转型后无法访问。

只能访问父类定义的成员

A ab = new B();
ab.name = "张三";  // A类中定义的属性
// ab.sex = "男";  // 编译错误:A类中没有sex属性

重写方法优先调用子类实现

// B类重写了run()方法
ab.run();  // 输出:"B跑的很快"

无法直接调用子类特有的方法

// B类的fly()方法是特有方法
// ab.fly();  // 编译错误

编译过程

编译阶段:

Test 类被编译成 Test.class。
A 类被编译成 A.class。
B 类被编译成 B.class,需要 A.class 的支持。
类加载阶段:

A.class 和 B.class 被加载到方法区。
运行阶段:

创建 B 类型的对象,并将其赋值给 A 类型的变量 ab。
调用 ab.run(),由于 ab 实际上引用的是 B 类对象,因此调用 B 中的 run 方法。
调用 ab.eat("张三"),由于 eat 方法在 A 类中定义且未在 B 类中重写,因此调用 A 类中的 eat 方法。

列题:

public class A {public String show(D obj) {return ("A and D");}public String show(A obj) {return ("A and A");} 
}public class B extends A{public String show(B obj){return ("B and B");}public String show(A obj){return ("B and A");} 
}public class C extends B{
}public class D extends B{
}public class Test {public static void main(String[] args) {A a1 = new A();A a2 = new B();B b = new B();C c = new C();D d = new D();System.out.println("1--" + a1.show(b));System.out.println("2--" + a1.show(c));System.out.println("3--" + a1.show(d));System.out.println("4--" + a2.show(b));System.out.println("5--" + a2.show(c));System.out.println("6--" + a2.show(d));System.out.println("7--" + b.show(b));System.out.println("8--" + b.show(c));System.out.println("9--" + b.show(d));      }
}

输出结果:

A and A
解析:a1 调用的是 A 类中的方法,其中有 show(D) 和 show(A) 两个重载方法。由于 b 被向上转型到 A,a1.show(b) 调用的是 A 类中的 show(A) 方法,输出 A and A。这在 a1 是 A 类型,且 b 的类型向上转型的情况下是准确的。

A and A
解析:和第一个选项相似,a1 调用的是 A 类的方法,C继承于B,b 向上转型到 A,因此调用 show(A) 方法,输出 A and A。这个选项与第一个选项的解释相同。

A and D
解析:a1 调用的是 A 类的方法,其中有 show(D) 和 show(A) 两个重载方法。如果 b 实际上是 D 类型,那么在 A 类中调用 show(D) 方法会输出 A and D。

B and A
解析:a2 是 B 类型,但由于方法重写,它调用的是 B 类中的 show(A) 方法。这个选项需要 B 类重写 A 类中的 show(A) 方法并且输出 B and A。

B and A
解析:类似于第四个选项,a2 是 B 类型,调用的是 B 类中的 show(A) 方法。这里需要 a2 向上转型到 A,调用 B 类的 show(A) 方法,输出 B and A。

A and D
解析:与第三个选项相似,这个结果表明 a2 调用的是 A 类中的 show(D) 方法,输出 A and D。需要 b 实际上是 D 类型或其子类。

B and B
解析:b 是 B 类型,B 类中的方法可以被调用,可能包括 show(D) 和 show(A) 方法,这里输出 B and B。这表明 B 类中的方法重写了 A 类中的方法。

B and B
解析:和第七个选项类似,这个结果表明 b 是 B 类型,由于继承和方法重写,输出 B and B。

A and D
解析:b 是 B 类型,调用了 A 类中的 show(D) 方法,输出 A and D。这表明 b 实际上是 D 类型或其子类,且重载方法选择为 show(D)。

  • a1 是 A 类型的引用,指向 A 对象
  • 对于 a1.show (b) 和 a1.show (c),参数 b 和 c 都是 B 的子类,向上转型为 A,因此调用 show (A)
  • 对于 a1.show (d),参数 d 是 D 类型,直接匹配 show (D)
  • a2 是 A 类型的引用,指向 B 对象
  • 对于 a2.show (b) 和 a2.show (c),参数 b 和 c 向上转型为 A,调用重写的 show (A) 方法
  • 对于 a2.show (d),参数 d 是 D 类型,直接匹配 show (D) 方法(B 中未重写该方法,因此调用 A 的实现)
  • b 是 B 类型的引用,指向 B 对象
  • 对于 b.show (b),直接匹配 B 的 show (B) 方法
  • 对于 b.show (c),参数 c 是 B 的子类,向上转型为 B,调用 B 的 show (B) 方法
  • 对于 b.show (d),参数 d 是 D 类型,向上转型为 A,调用 B 的 show (A) 方法(这里可能存在争议,根据 Java 的方法匹配规则,优先匹配最具体的类型,但由于 B 中没有 show (D),因此向上转型为 A)

总结

向上转型是面向对象编程中实现多态性的重要手段。它允许子类对象被当作父类对象来处理,从而提高了代码的灵活性和可维护性。通过向上转型,可以在不修改现有代码的情况下,扩展程序的功能。

相关文章:

  • Vmware 最新下载教程和安装教程,外带免下载文件
  • 【软件设计师:多媒体】14.多媒体技术及其应用
  • 【C/C++】C语⾔内存函数
  • 空间复杂度** 与 **所需辅助空间**
  • LVGL源码学习之渲染、更新过程(1)---标记和激活
  • 我国脑机接口市场规模将破38亿元,医疗领域成关键突破口
  • SDC命令详解:使用all_inputs命令进行查询
  • 每天批次导入 100 万对账数据到 MySQL 时出现死锁
  • 一、对linux驱动文件编写时结构认识与记录
  • gpu硬件,gpu驱动,cuda,CUDA Toolkit,cudatoolkit,cudnn,nvcc概念解析
  • 操作系统 第2章节 进程,线程和作业
  • 【PhysUnits】3.3 SI 基础量纲单位(units/base.rs)
  • Leetcode刷题 由浅入深之字符串——541. 反转字符串Ⅱ
  • 振动临近失效状态,怎么频谱会是梳子?
  • API请求参数有哪些?
  • Modbus RTU 详解 + FreeMODBUS移植(附项目源码)
  • 【算法】:滑动窗口
  • 常见图像融合算法(alpha和金字塔融合)
  • 使用智能表格做FMEDA
  • Mysql--基础知识点--91.1--慢查询日志
  • 巴军事行动致印度70%电网瘫痪
  • 临港新片区:发布再保险、国际航运、生物医药3个领域数据出境操作指引
  • 深圳两家会所涉卖淫嫖娼各被罚7万元逾期未缴,警方发催告书
  • 71岁导演詹姆斯・弗雷病逝,曾执导《纸牌屋》、麦当娜MV
  • 迪拜金融市场CEO:2024年市场表现出色,超八成新投资者来自海外
  • 印媒证实:至少3架印军战机7日在印控克什米尔地区坠毁