Apabila program berjalan, panggilan kaedah ialah operasi yang paling biasa dan kerap
Panggilan kaedah tidak sama dengan pelaksanaan kaedah:
Satu-satunya tugas dalam fasa panggilan kaedah adalah untuk menentukan versi kaedah yang dipanggil, iaitu kaedah yang dipanggil
Ia tidak melibatkan proses berjalan tertentu di dalam kaedah
Proses penyusunan fail Kelas tidak termasuk langkah sambungan dalam kompilasi tradisional
Semua panggilan kaedah dalam fail Kelas ialah rujukan simbolik yang disimpan dalam fail Kelas, dan Ia bukan alamat kemasukan kaedah dalam susun atur memori yang sedang berjalan, iaitu rujukan langsung sebelumnya:
Ini menjadikan Java mempunyai keupayaan pengembangan dinamik yang lebih berkuasa
Pada masa yang sama, ia juga menjadikan proses panggilan kaedah Java agak rumit
Rujukan langsung kaedah sasaran perlu ditentukan semasa pemuatan kelas atau pun semasa masa jalan
Kaedah sasaran dalam semua panggilan kaedah ialah rujukan kepada kumpulan tetap dalam fail Kelas
Dalam fasa pemuatan dan analisis kelas, ia akan Menukar beberapa rujukan simbol kepada rujukan langsung:
Kaedah ini mempunyai versi panggilan yang boleh ditentukan sebelum program sebenarnya dilaksanakan , dan versi panggilan kaedah ini tidak boleh diubah semasa masa jalan
Dalam erti kata lain, sasaran panggilan diselesaikan dalam kod program dan mesti ditentukan apabila pengkompil ini juga dipanggil analisis kaedah
Di Java, ia mematuhi "masa penyusunan" Ia dapat dilihat bahawa terdapat dua kategori utama kaedah "masa berjalan tidak boleh berubah":
Kaedah statik: berkaitan secara langsung dengan jenis
Kaedah peribadi: tidak boleh diakses secara luaran
Ciri kedua-dua kaedah ini menentukan bahawa kedua-dua kaedah tidak boleh ditindih melalui pewarisan atau kaedah lain, jadi ia sesuai untuk menghuraikan semasa fasa pemuatan kelas
Kaedah bukan maya: <.> Semasa fasa pemuatan kelas, rujukan simbol akan dihuraikan sebagai rujukan langsung kepada kaedah
Kaedah maya: Semasa fasa pemuatan kelas, rujukan simbol tidak akan diselesaikan sebagai rujukan langsung kepada kaedah
Kecuali kaedah bukan maya di atas, kaedah lain Semua kaedah adalah kaedah mayaPenghantaran statikpublic class StaticDispatch { static abstract class Human { } static class Man extends Human { } static class Woman extends Human { } public static void sayHello(Human guy) { System.out.println("Hello, Guy!"); } public static void sayHello(Man guy) { System.out.println("Hello, Gentleman!"); } public static void sayHello(woman guy) { System.out.println("Hello, Lady!"); } public static void main(String[] args) { Human man = new Man(); Human women = new Woman(); sayHello(man); sayHello(woman); } }
Manusia = new Human();
ialah jenis statik pembolehubah Human
ialah jenis sebenar pembolehubah Man
Kedua-dua jenis statik dan jenis sebenar akan berubah dalam atur cara:
Jenis statik:
Jenis sebenar:
Human human = new Man(); sayHello(man); sayHello((Man)man); // 类型转换,静态类型变化,转型后的静态类型一定是Man man = new woman(); // 实际类型变化,实际类型是不确定的 sayHello(man); sayHello((Woman)man); // 类型转换,静态类型变化
Penghantaran statik:
: Kaedah terlebih beban
Penghantaran statik berlaku semasa fasa penyusunan, jadi penghantaran statik ditentukan Tindakan yang dihantar tidak dilaksanakan oleh mesin maya, tetapi diselesaikan oleh pengkompil
Memandangkan literal tidak memaparkan jenis statik, ia hanya boleh difahami dan disimpulkan melalui peraturan bahasapublic class LiteralTest { public static void sayHello(char arg) { System.out.println("Hello, char!"); } public static void sayHello(int arg) { System.out.println("Hello, int!"); } public static void sayHello(long arg) { System.out.println("Hello, long!"); } public static void sayHello(Character arg) { System.out.println("Hello, Character!"); } public static void main(String[] arg) { sayHello('a'); } }
public class LiteralTest { public static void sayHello(String arg) { // 新增重载方法 System.out.println("Hello, String!"); } public static void sayHello(char arg) { System.out.println("Hello, char!"); } public static void sayHello(int arg) { System.out.println("Hello, int!"); } public static void sayHello(long arg) { System.out.println("Hello, long!"); } public static void sayHello(Character arg) { System.out.println("Hello, Character!"); } public static void main(String[] args) { Random r = new Random(); String s = "abc"; int i = 0; sayHello(r.nextInt() % 2 != 0 ? s : 1 ); // 编译错误 sayHello(r.nextInt() % 2 != 0 ? 'a' : false); //编译错误 } }
public class DynamicDispatch { static abstract class Human { protected abstract void sayHello(); } static class Man extends Human { @override protected void sayHello() { System.out.println("Man Say Hello!"); } } static class Woman extends Human { @override protected void sayHello() { System.out.println("Woman Say Hello!"); } } public static void main(String[] args) { Human man = new Man(); Human women = new Woman(); man.sayHello(); woman.sayHello(); man = new Woman(); man.sayHello(); } }
ManusiaDua Pembolehubah lelaki dan wanita melakukan tingkah laku yang berbeza apabila memanggil kaedah sayHello()
manmelaksanakan kaedah berbeza dalam dua panggilan
: jenis sebenar kedua-dua pembolehubah adalah berbeza
Cara mesin maya Java menghantar versi pelaksanaan kaedah mengikut jenis sebenar: Bermula daripada proses carian polimorfik arahan invokevirtual, apabila invokevirtual arahan sedang berjalan Proses penghuraian dibahagikan secara kasar kepada langkah-langkah berikut:
C
Jika kaedah yang sepadan dengan deskriptor dan nama ringkas dalam pemalar ditemui dalam jenis C, maka pengesahan kebenaran akses dilakukan Jika pengesahan diluluskan, rujukan langsung kepada kaedah ini dikembalikan, dan proses carian tamat; Jika pengesahan gagal, pengecualian java.lang.illegalAccessError dilemparkan
Jika ia tidak dijumpai, setiap elemen jenis C ditandakan dari bawah ke atas mengikut perhubungan warisan Kelas induk melaksanakan langkah kedua proses carian dan pengesahan
Jika tiada kaedah yang sesuai ditemui, a java.lang.AbstractMethodError pengecualian
Langkah pertama dalam pelaksanaan arahan invokevirtual adalah untuk menentukan penerima sebenar pada jenis runtime, jadi arahan invokevirtual dalam dua panggilan menyelesaikan rujukan simbol kaedah kelas dalam kolam malar kepada rujukan langsung yang berbeza
Ini ialah proses penghantaran yang menentukan versi pelaksanaan kaedah berdasarkan jenis sebenar semasa masa jalan Ia dipanggil penghantaran dinamik
Pelaksanaan penghantaran dinamik mesin mayaMod analisis konsep mesin maya adalah penghantaran statik dan penghantaran dinamik Ia boleh difahami bahawa mesin maya akan"akan Apa yang perlu dilakukan" Soalan ini
Mesin maya"Bagaimana untuk melakukannya secara khusus" Akan terdapat perbezaan dalam pelbagai pelaksanaan mesin maya:
Memandangkan penghantaran dinamik adalah tindakan yang sangat kerap, dan proses pemilihan versi kaedah penghantaran dinamik memerlukan pencarian sasaran yang sesuai kaedah dalam metadata kaedah kelas pada masa jalan
jadual kaedah maya (vtable) untuk kelas dalam kawasan kaedah, dan gunakan indeks jadual kaedah maya dan bukannya carian metadata untuk meningkatkan prestasi
Jadual kaedah maya menyimpan alamat kemasukan sebenar setiap kaedah:
Kaedah dengan tandatangan yang sama, dalam kelas induk, anak Jadual kaedah maya kelas mempunyai nombor indeks yang sama:
Dengan cara ini, apabila jenis perubahan, anda hanya perlu menukar jadual kaedah untuk dicari, dan kaedah yang diperlukan boleh ditukar daripada jadual kaedah maya yang berbeza mengikut indeks Alamat entrijadual kaedah biasanya dimulakan fasa sambungan fasa pemuatan kelas:
Selepas menyediakan nilai awal pembolehubah kelas, mesin maya juga akan dimulakanAtas ialah kandungan terperinci Menggunakan panggilan kaedah Java untuk menyelesaikan penghantaran statik dan penghantaran dinamik. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!