cari
RumahJavajavaTutorialJava中静态分派和动态分派的介绍(代码示例)

本篇文章给大家带来的内容是关于Java中静态分派和动态分派的介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。

最近复习JVM的知识,对于静态分派和动态分派的理解有点混乱,于是自己尝试写写代码,在分析中巩固知识。

有如下一段代码,请问每一段分别输出什么?

package com.khlin.my.test;

class Base {

    public static void foo() {
        System.out.println("Base.foo() invoked");
    }

    public void bar(int c) {
        System.out.println("Base.bar(int) invoked");
    }

    public void bar(Character c) {
        System.out.println("Base.bar(Character) invoked");
    }

    public void baz(Object o) {
        System.out.println("Base.baz(Object) invoked");
    }

    public void baz(Integer i) {
        System.out.println("Base.baz(Integer) invoked");
    }

}

class Child extends Base {
    public static void foo() {
        System.out.println("Child.foo() invoked");
    }

    public void bar(Character c) {
        System.out.println("Child.bar(Character) invoked");
    }

    public void bar(char c) {
        System.out.println("Child.bar(char) invoked");
    }
}

public class App {

    public static void main(String[] args) {
        Base child = new Child();

        System.out.println("第1段输出:");
        child.foo();
        child.bar(new Character('C'));

        System.out.println("第2段输出:");
        Object integer = new Integer(100);
        child.baz(integer);

        System.out.println("第3段输出:");
        child.bar('C');

    }
}

下面我简单地介绍一下从代码编译到方法调用的整个过程。

· 编译

先看看第1段输出,child.foo()是调用父类还是子类的静态方法呢?

在编译阶段,发生了静态分派

1 Base child = new Child();

在我们创建一个对象时,如上图,Base称为变量的的静态类型(Static Type), 或者叫做外观类型(Apparent Type),后面的Child则称为变量的实际类型(Actual Type)。

所有依赖静态类型来定位方法执行版本的分派动作,称为静态分派。静态分派的典型应用是方法重载,其发生在编译阶段,因此确定静态分派的动作实际上不是由虚拟机来执行的。

方法的接收者(Reciever) 和方法的参数统称为方法的宗量,根据分派基于多少种宗量,可以将分派划分为单分派和多分派两种。

在静态分派的时候,选择目标方法的依据有两点,一是静态类型是Base还是Child,二是方法的参数类型。因此,静态分派是多分派。

接下来,我们来看看“第1段输出”代码生成的指令。通过javap -v App.class指令得出如下结果,可以看到第18和第31行两条指令的符号引用,和上述分析一致:child的静态类型是Base,所以选择Base类的方法;通过无参数和Character类型,分别确定是具体哪个方法版本。

但最终两者的行为不一样,child.foo() 调用的是静态类型Base的foo(),而child.bar(new Character('C')) 则是调用实际类型Child的方法。

原因就是出在两条指令不一样:invokestatic和invokevirtual

在Java虚拟机里面提供了5条方法调用字节码指令:

invokestatic:调用静态方法

invokespecial:调用实例构造器7e51f00a783d7eb8f68358439dee7daf方法、私有方法和父类方法

invokevirtual: 调用所有的虚方法

invokeinterface:调用接口方法,会在运行时再确定 一个实现此接口的对象

invokedynamic:先在运行时动态解析出调用点限定符所引用的方法,然后再执行该方法,在此之前的4条调用指令,分派逻辑是固化在Java虚拟机内部的,而invokedynamic是由用户所设定的引导方法决定的。

具体原因是不同的指令在下一阶段(类加载的解析)的行为不一样,暂时先放到一边,我们再看看第2段输出的指令。

可以看出,在静态分派时,是根据传入方法的参数的静态类型来决定调用的方法版本,虽然有baz(Integer)的方法,但是传入的参数integer的静态类型是Object,所以调用了baz(Object)。

再来看看第3段输出的指令,我们知道符号引用肯定还是Base类里的方法(尽管Child类里有参数一样的bar(char c) 方法),但Base里没有一模一样参数(char类型) 的方法,不会报错吗?会调用哪个方法呢?

原来,编译器虽然能确定出方法的重载版本,但在很多情况下这个重载版本并不是“唯一的”,往往只能确定一个“更加合适”的版本。

· 类加载之解析

 解析阶段是虚拟机将常量池内的符号引用替换为直接引用的过程。

只要能被invokestatic和invokespecial指令调用的方法,都可以在解析阶段中确定唯一的调用版本,符合这个条件的有静态方法,私有方法,实例构造器,父类方法4类,它们在类加载的时候就会把符号引用解析为该方法的直接引用。这些方法可以称为非虚方法,其他方法称为非虚方法(除了final方法)。

final修饰的方法,虽然是使用invokevirtual指令来调用,但由于它无法被覆盖,没有其他版本,因此也是非虚方法。

回到第1段输出,child.foo()是invokestatic指令,那么在解析阶段,就会替换成直接引用,具体的类也就确定下来了,因此调用的是静态类型Base.foo()。

而child.bar(new Character('C')) 是invokevirtual, 在这个阶段可以确定调用的方法签名,但还不能确定方法的接收者的实际类型。它将由动态分派来完成确定。由于只有一个宗量影响,因此动态分派是单分派。

方法接收者的实际类型在下一阶段确定。

· 运行期的方法调用

在运行期根据实际类型确定方法执行版本的分派过程称为动态分派。

最终输出结果是:

Atas ialah kandungan terperinci Java中静态分派和动态分派的介绍(代码示例). Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan
Artikel ini dikembalikan pada:博客园. Jika ada pelanggaran, sila hubungi admin@php.cn Padam
Adakah terdapat teknologi baru yang mengancam atau meningkatkan kemerdekaan platform Java?Adakah terdapat teknologi baru yang mengancam atau meningkatkan kemerdekaan platform Java?Apr 24, 2025 am 12:11 AM

Teknologi yang muncul menimbulkan ancaman dan meningkatkan kemerdekaan platform Java. 1) Teknologi pengkomputeran awan dan kontena seperti Docker meningkatkan kemerdekaan platform Java, tetapi perlu dioptimumkan untuk menyesuaikan diri dengan persekitaran awan yang berbeza. 2) WebAssembly menyusun kod Java melalui GraalVM, memperluaskan kemerdekaan platformnya, tetapi ia perlu bersaing dengan bahasa lain untuk prestasi.

Apakah pelaksanaan JVM yang berbeza, dan adakah mereka semua menyediakan tahap kemerdekaan platform yang sama?Apakah pelaksanaan JVM yang berbeza, dan adakah mereka semua menyediakan tahap kemerdekaan platform yang sama?Apr 24, 2025 am 12:10 AM

Pelaksanaan JVM yang berbeza dapat memberikan kemerdekaan platform, tetapi prestasi mereka sedikit berbeza. 1. OracleHotspot dan OpenJDKJVM melakukan sama seperti kemerdekaan platform, tetapi OpenJDK mungkin memerlukan konfigurasi tambahan. 2. IBMJ9JVM melakukan pengoptimuman pada sistem operasi tertentu. 3. Graalvm menyokong pelbagai bahasa dan memerlukan konfigurasi tambahan. 4. AzulzingJVM memerlukan pelarasan platform tertentu.

Bagaimanakah kebebasan platform mengurangkan kos pembangunan dan masa?Bagaimanakah kebebasan platform mengurangkan kos pembangunan dan masa?Apr 24, 2025 am 12:08 AM

Kemerdekaan platform mengurangkan kos pembangunan dan memendekkan masa pembangunan dengan menjalankan set kod yang sama pada pelbagai sistem operasi. Khususnya, ia ditunjukkan sebagai: 1. Mengurangkan masa pembangunan, hanya satu set kod yang diperlukan; 2. Mengurangkan kos penyelenggaraan dan menyatukan proses ujian; 3. Penyebaran cepat dan kerjasama pasukan untuk memudahkan proses penempatan.

Bagaimanakah kemerdekaan platform Java memudahkan penggunaan semula kod?Bagaimanakah kemerdekaan platform Java memudahkan penggunaan semula kod?Apr 24, 2025 am 12:05 AM

Java'splatformindependencefacilitatescodereusebyallowbytytecodetorunonanyplatformWithAjvm.1) DeveloptersCanWriteCodeOnceforconsistentBeHavioracrossplatforms.2)

Bagaimana anda menyelesaikan masalah khusus platform dalam aplikasi Java?Bagaimana anda menyelesaikan masalah khusus platform dalam aplikasi Java?Apr 24, 2025 am 12:04 AM

Untuk menyelesaikan masalah khusus platform dalam aplikasi Java, anda boleh mengambil langkah-langkah berikut: 1. Gunakan kelas sistem Java untuk melihat sifat sistem untuk memahami persekitaran yang sedang berjalan. 2. Gunakan kelas fail atau java.nio.file untuk memproses laluan fail. 3. Muatkan perpustakaan tempatan mengikut keadaan sistem operasi. 4. Gunakan VisualVM atau JProfiler untuk mengoptimumkan prestasi silang platform. 5. Pastikan persekitaran ujian selaras dengan persekitaran pengeluaran melalui kontena Docker. 6. Gunakan githubactions untuk melakukan ujian automatik pada pelbagai platform. Kaedah ini membantu menyelesaikan masalah khusus platform dalam aplikasi Java.

Bagaimanakah subsistem loader kelas dalam JVM menyumbang kepada kebebasan platform?Bagaimanakah subsistem loader kelas dalam JVM menyumbang kepada kebebasan platform?Apr 23, 2025 am 12:14 AM

Loader kelas memastikan konsistensi dan keserasian program Java pada platform yang berbeza melalui format fail kelas bersatu, pemuatan dinamik, model delegasi induk dan bytecode bebas platform, dan mencapai kemerdekaan platform.

Adakah pengkompil Java menghasilkan kod khusus platform? Menjelaskan.Adakah pengkompil Java menghasilkan kod khusus platform? Menjelaskan.Apr 23, 2025 am 12:09 AM

Kod yang dihasilkan oleh pengkompil Java adalah platform bebas, tetapi kod yang akhirnya dilaksanakan adalah platform khusus. 1. Kod sumber Java disusun ke dalam bytecode bebas platform. 2. JVM menukar bytecode ke dalam kod mesin untuk platform tertentu, memastikan operasi silang platform tetapi prestasi mungkin berbeza.

Bagaimanakah JVM mengendalikan multithreading pada sistem operasi yang berbeza?Bagaimanakah JVM mengendalikan multithreading pada sistem operasi yang berbeza?Apr 23, 2025 am 12:07 AM

Multithreading adalah penting dalam pengaturcaraan moden kerana ia dapat meningkatkan respons program dan penggunaan sumber dan mengendalikan tugas serentak yang kompleks. JVM memastikan konsistensi dan kecekapan multithreads pada sistem operasi yang berbeza melalui pemetaan benang, mekanisme penjadualan dan mekanisme kunci penyegerakan.

See all articles

Alat AI Hot

Undresser.AI Undress

Undresser.AI Undress

Apl berkuasa AI untuk mencipta foto bogel yang realistik

AI Clothes Remover

AI Clothes Remover

Alat AI dalam talian untuk mengeluarkan pakaian daripada foto.

Undress AI Tool

Undress AI Tool

Gambar buka pakaian secara percuma

Clothoff.io

Clothoff.io

Penyingkiran pakaian AI

Video Face Swap

Video Face Swap

Tukar muka dalam mana-mana video dengan mudah menggunakan alat tukar muka AI percuma kami!

Alat panas

EditPlus versi Cina retak

EditPlus versi Cina retak

Saiz kecil, penyerlahan sintaks, tidak menyokong fungsi gesaan kod

Notepad++7.3.1

Notepad++7.3.1

Editor kod yang mudah digunakan dan percuma

SublimeText3 versi Cina

SublimeText3 versi Cina

Versi Cina, sangat mudah digunakan

Dreamweaver Mac版

Dreamweaver Mac版

Alat pembangunan web visual

MinGW - GNU Minimalis untuk Windows

MinGW - GNU Minimalis untuk Windows

Projek ini dalam proses untuk dipindahkan ke osdn.net/projects/mingw, anda boleh terus mengikuti kami di sana. MinGW: Port Windows asli bagi GNU Compiler Collection (GCC), perpustakaan import yang boleh diedarkan secara bebas dan fail pengepala untuk membina aplikasi Windows asli termasuk sambungan kepada masa jalan MSVC untuk menyokong fungsi C99. Semua perisian MinGW boleh dijalankan pada platform Windows 64-bit.