Java单继承实现原理

Java单继承实现原理

一 . 多态的分类

首先在聊多态的原理之前我们先对多态分个类

  • 编译时多态
  • 运行时多态

1. 什么是编译时多态

编译时多态是静态的 , 主要是指重载方法 , 简单来说就是同一个方法名称不同的参数列表

public class PolymorphismExample {

    // 方法1:无参数
    public void display() {
        System.out.println("Display without parameters");
    }

    // 方法2:一个整数参数
    public void display(int number) {
        System.out.println("Display with one integer parameter: " + number);
    }

    // 方法3:两个整数参数
    public void display(int number1, int number2) {
        System.out.println("Display with two integer parameters: " + number1 + " and " + number2);
    }

    // 方法4:一个字符串参数
    public void display(String str) {
        System.out.println("Display with one string parameter: " + str);
    }

    public static void main(String[] args) {
        PolymorphismExample obj = new PolymorphismExample();

        // 调用无参数的方法
        obj.display();

        // 调用一个整数参数的方法
        obj.display(10);

        // 调用两个整数参数的方法
        obj.display(10, 20);

        // 调用一个字符串参数的方法
        obj.display("Hello, World!");
    }
}

2. 什么是运行时多态

运行时多态是面向对象编程中的一个重要概念,它允许在运行时根据对象的实际类型来调用相应的方法。这种多态性是通过动态绑定(也称为晚期绑定)来实现的,意味着方法调用的解析是在程序运行时进行的,而不是在编译时。

在Java中,运行时多态主要依赖于以下几个方面:

  1. 继承:子类可以继承父类的方法,并且可以重写这些方法。
  2. 方法重写(Override):子类可以提供一个具有相同名称和参数列表的方法实现,这将覆盖父类中的方法。
  3. 动态方法调度:在运行时,Java虚拟机(JVM)会根据对象的实际类型来决定调用哪个方法。
class Animal {
    public void makeSound() {
        System.out.println("Some generic sound");
    }
}

class Dog extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Bark");
    }
}

class Cat extends Animal {
    @Override
    public void makeSound() {
        System.out.println("Meow");
    }
}

public class RuntimePolymorphismExample {
    public static void main(String[] args) {
        Animal myAnimal = new Dog();
        myAnimal.makeSound(); // 输出 "Bark"

        Animal myOtherAnimal = new Cat();
        myOtherAnimal.makeSound(); // 输出 "Meow"

        // 使用多态性,我们可以将不同类型的对象赋值给同一引用类型
        makeSound(new Dog()); // 输出 "Bark"
        makeSound(new Cat()); // 输出 "Meow"
    }

    public static void makeSound(Animal animal) {
        animal.makeSound(); // 这里会根据传入对象的实际类型调用相应的makeSound方法
    }
}

二. 底层原理

RTTI

多态实现的技术基础是 RTTI,即 Run-Time Type Identification(运行时类型判定) , RTTI在多态中的作用是,它允许程序在运行时确定对象的实际类型,并根据这个类型信息来调用相应的方法。这使得多态成为可能,因为程序可以在不知道对象确切类型的情况下,通过RTTI来动态地调用正确的方法实现。

Java 源码编译器将 Java 文件编译成 .class 文件,然后通过类装载器将 .class 文件装载到 JVM 的方法区中 并建立对应类的类型信息类型信息包括了方法代码,类变量、成员变量、以及方法表。

而在方法区的类型信息中会创建一个指针 , 该指针会指向一张记录该类方法入口的表也就是方法表, 那么什么是方法表?

方法表

在这里插入图片描述

由于Java的单继承机制,一个类只能继承一个父类,而所有的类又都继承自Object类。方法表中最先存放的是Object类的方法,接下来是该类的父类的方法,最后是该类本身的方法。

这里关键的地方在于,如果子类改写了父类的方法,那么子类和父类的那些同名方法共享一个方法表项,都被认作是父类的方法。

在这里插入图片描述

而对于方法表 , 其中的所有项都是通过指针指向其实现方法.

一旦JVM知道了实际对象的类型,它会查找该类型对应的方法表(vtable)。方法表是一个包含指向方法实现的指针的结构。

如何实现?

在Java中,当通过父类的引用调用一个方法时,JVM(Java虚拟机)会使用动态分派来确定实际调用的方法。这个过程是自动的,不需要程序员显式地查看引用指向的实际对象类型。以下是这个过程的详细说明:

  1. 类型信息存储
    • 在Java中,每个对象都包含一个指向其类(Class)对象的引用。这个引用存储在对象的头部,通常被称为“对象头”。
    • 类对象包含了类的元数据,包括类的名称、字段、方法等信息,以及一个指向该类方法表的引用。
  2. 动态分派
    • 当一个方法调用发生在继承体系中时,JVM会使用动态分派来确定应该执行哪个方法。
    • JVM会查看对象头中的类引用,找到实际对象的类对象 , 获取其对应的类型。
    • 然后,JVM会根据类对象中的方法表来查找应该调用的方法。
  3. 方法表查找
    • JVM会在实际对象的方法表中查找与调用的方法名和参数匹配的方法。如果子类重写了父类的方法,那么子类的方法表中会包含指向子类方法实现的指针, 子类的方法表中会包含一个指向子类方法实现的引用,而不是父类的方法实现。
  4. 方法调用
    • 一旦找到正确的方法引用,JVM就会调用这个方法。
    • 这个过程是透明的,对程序员来说是不可见的,JVM自动处理了所有的分派逻辑。

猜你喜欢

转载自blog.csdn.net/xiugtt6141121/article/details/143421020