【无标题】

为什么重写父类object类中的toString方法后,println调用的tostring方法是重写的方法而不是object类中的toString方法?

当你在子类中重写父类 `Object` 类的 `toString` 方法后,使用 `println` 输出该子类对象时调用的是子类中重写的 `toString` 方法而不是 `Object` 类中的默认 `toString` 方法,这是由于Java中的动态方法调度机制(也称为后期绑定或运行时多态)。
### 动态方法调度
在Java中,所有非静态方法(包括实例方法)默认都是虚拟的(virtual),这意味着它们可以在运行时根据实际的对象类型来决定调用哪个版本的方法。具体来说:
- **当一个对象被创建并调用其方法时**,JVM会查找该对象的实际类型,并调用与之匹配的最具体的方法实现。
  • 即使这个方法是通过指向该对象的父类类型的引用来调用的,也会执行这一规则。这是因为Java使用了**动态方法分派**的方式,在运行时根据对象的实际类型来确定调用哪个方法。
### 示例代码
考虑以下示例:
java 复制代码
class Parent {
    @Override
    public String toString() {
        return "This is Parent class";
    }
}

class Child extends Parent {
    @Override
    public String toString() {
        return "This is Child class";
    }
}

public class Main {
    public static void main(String[] args) {
        Parent obj = new Child(); // 用父类引用指向子类对象
        System.out.println(obj); // 将输出"This is Child class"
    }
}
在这个例子中,尽管 `obj` 是 `Parent` 类型的引用,但它实际上指向的是 `Child` 类的一个实例。因此,当 `System.out.println(obj)` 被调用时,JVM识别到 `obj` 实际上是一个 `Child` 类的实例,并调用了 `Child` 类中重写的 `toString` 方法,而不是 `Parent` 类中的 `toString` 方法。
### 多态性
这种行为支持了面向对象编程中的一个重要概念------**多态性**。它允许基于对象的实际类型来调用适当的方法,这使得代码更加灵活和可扩展。对于像 `toString` 这样的方法,它可以让你为不同的类提供具体的字符串表示形式,从而提高代码的可读性和维护性。
综上所述,当你重写了 `Object` 类中的 `toString` 方法之后,`println` 函数调用的是子类中重写的 `toString` 方法,这是因为Java在运行时能够识别对象的真实类型,并据此选择正确的 `toString` 方法进行调用。

可是Parent类中的虚方法表,没有Child中重写的方法啊

在Java中,当你创建一个子类对象时,例如 `Child` 类继承自 `Parent` 类,并且在 `Child` 类中重写了 `toString` 方法,那么这个子类对象实际上包含了一个指向其虚方法表(vtable)的指针。这个虚方法表包含了该对象可以调用的所有实例方法的地址。

### 虚方法表的工作机制

1. **虚方法表的构建**:当一个类被加载并初始化时,JVM会为这个类生成一个虚方法表。对于每个类,这个表包含了从该类及其所有父类继承来的虚方法(即非私有、非静态的方法)。如果某个方法在子类中被重写,则虚方法表中对应条目的地址将指向子类中实现的方法;如果没有被重写,则指向父类中的实现。

2. **多态性与动态调度**:当你使用父类类型的引用来指向子类对象时,尽管引用类型是父类,但实际的对象类型决定了调用哪个版本的方法。这是因为JVM根据对象的实际类型来查找相应的虚方法表,并找到正确的实现方法。因此,即使是在父类中声明的引用变量,如果它指向的是子类对象,那么调用的方法也是子类中重写的版本。

### 示例解释

假设你有如下代码:

java 复制代码
class Parent {
    public String toString() {
        return "This is Parent class";
    }
}

class Child extends Parent {
    @Override
    public String toString() {
        return "This is Child class";
    }
}

public class Main {
    public static void main(String[] args) {
        Parent obj = new Child(); // 父类引用指向子类对象
        System.out.println(obj); // 输出"This is Child class"
    }
}

在这个例子中:

**- 当 `new Child()` 创建一个 `Child` 类型的对象时,JVM为这个对象生成了一个虚方法表,其中包含了从 `Parent` 继承的方法以及 `Child` 中定义或重写的方法。

  • 如果 `Child` 类重写了 `toString` 方法,那么在 `Child` 的虚方法表中,`toString` 方法对应的条目将指向 `Child` 类中的实现。
  • 在执行 `System.out.println(obj)` 时,尽管 `obj` 是 `Parent` 类型的引用,但由于它是对 `Child` 对象的引用,JVM会查询 `Child` 对象的虚方法表来找到 `toString` 方法的正确实现,并调用 `Child` 类中重写的 `toString` 方法。**

### 关键点

**- **虚方法表是基于对象的实际类型**:无论引用的声明类型是什么,JVM都会根据对象的实际类型来决定使用哪个虚方法表,从而确保调用了最具体的实现。

  • **重写方法覆盖了父类方法在虚方法表中的位置**:当子类重写父类的方法时,它实际上是在子类的虚方法表中更新了该方法的实现地址,这样就能保证总是调用到最新的实现。**

综上所述,虽然 `Parent` 类的虚方法表不直接包含 `Child` 类中重写的方法,但是由于 `Child` 类有自己的虚方法表,且在运行时JVM能够根据对象的实际类型找到并调用正确的虚方法表,所以能够调用到子类中重写的 `toString` 方法。

相关推荐
YuTaoShao2 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
源码_V_saaskw3 小时前
JAVA图文短视频交友+自营商城系统源码支持小程序+Android+IOS+H5
java·微信小程序·小程序·uni-app·音视频·交友
超浪的晨3 小时前
Java UDP 通信详解:从基础到实战,彻底掌握无连接网络编程
java·开发语言·后端·学习·个人开发
双力臂4043 小时前
Spring Boot 单元测试进阶:JUnit5 + Mock测试与切片测试实战及覆盖率报告生成
java·spring boot·后端·单元测试
Edingbrugh.南空4 小时前
Aerospike与Redis深度对比:从架构到性能的全方位解析
java·开发语言·spring
QQ_4376643144 小时前
C++11 右值引用 Lambda 表达式
java·开发语言·c++
永卿0014 小时前
设计模式-迭代器模式
java·设计模式·迭代器模式
誰能久伴不乏4 小时前
Linux如何执行系统调用及高效执行系统调用:深入浅出的解析
java·服务器·前端
慕y2745 小时前
Java学习第七十二部分——Zookeeper
java·学习·java-zookeeper
midsummer_woo5 小时前
基于spring boot的医院挂号就诊系统(源码+论文)
java·spring boot·后端