Rumah  >  Artikel  >  Java  >  Menggunakan panggilan kaedah Java untuk menyelesaikan penghantaran statik dan penghantaran dinamik

Menggunakan panggilan kaedah Java untuk menyelesaikan penghantaran statik dan penghantaran dinamik

WBOY
WBOYke hadapan
2023-04-20 23:22:211293semak imbas

Panggilan kaedah

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

Analisis kaedah

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

Pengkelasan kaedah Java

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 statik

  • Kaedah peribadi

  • Pembina Instance

  • Kaedah kelas induk

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 maya

Penghantaran statik

public 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 statik berubah hanya apabila digunakan

  • Jenis statik pembolehubah itu sendiri tidak Berubah

  • Jenis statik akhir diketahui dalam pengkompil

Jenis sebenar:

  • Hasil daripada perubahan jenis sebenar ditentukan semasa masa jalan

  • Pengkompil tidak mengetahui jenis sebenar objek semasa penyusunan

Human human = new Man();
sayHello(man);
sayHello((Man)man);		// 类型转换,静态类型变化,转型后的静态类型一定是Man
man = new woman();		// 实际类型变化,实际类型是不确定的
sayHello(man);
sayHello((Woman)man);	// 类型转换,静态类型变化
Bila terlebih muatan, pengkompil menggunakan jenis statik parameter dan bukannya jenis sebenar sebagai asas untuk pertimbangan Jenis statik boleh diketahui semasa penyusunan:

Semasa fasa penyusunan, pengkompil Javac akan Menentukan versi yang terlebih muatan. untuk digunakan berdasarkan jenis statik parameter

Penghantaran statik:

  • Semua penghantaran yang bergantung pada penaipan statik untuk mencari versi pelaksanaan kaedah Tindakan

  • Aplikasi biasa

    : 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 bahasa

public 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(&#39;a&#39;);
	}
}
Pengkompil menganotasi kaedah terlampau beban dari atas ke bawah untuk mendapatkan output yang berbeza

Jika pengkompil tidak dapat menentukan jenis untuk menyesuaikan penukaran, ia akan menggesa jenis kekaburan dan enggan menyusun

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 ? &#39;a&#39; : false);	//编译错误
	}
}
Penghantaran dinamik

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();
	}
}
Ini tidak ditentukan berdasarkan jenis statik

  • Jenis statik

    ManusiaDua Pembolehubah lelaki dan wanita melakukan tingkah laku yang berbeza apabila memanggil kaedah sayHello()

  • pembolehubah

    manmelaksanakan kaedah berbeza dalam dua panggilan

Sebab fenomena ini

: 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:

  • Cari jenis sebenar objek yang ditunjuk oleh elemen pertama di bahagian atas tindanan operan, dilambangkan sebagai

    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

Intipati penulisan semula kaedah bahasa Java:

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 maya

Mod 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

  • Oleh itu, dalam pelaksanaan sebenar mesin maya, atas sebab prestasi, kebanyakan pelaksanaan sebenarnya tidak akan melakukan carian kerap sedemikian

  • "pengoptimuman kestabilan" yang paling biasa digunakan Caranya ialah dengan mencipta

    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:

  • Jika kaedah tidak digunakan dalam Penulisan Semula subkelas, entri alamat dalam jadual kaedah maya subkelas adalah konsisten dengan kemasukan alamat kaedah yang sama dalam kelas induk, dan kedua-duanya menunjuk kepada yang sebenar kemasukan kelas induk

  • Selepas menulis kaedah ini, alamat dalam jadual kaedah subkelas akan digantikan dengan alamat kemasukan yang menunjuk kepada kaedah sebenar subkelas

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 entri

jadual kaedah biasanya dimulakan fasa sambungan fasa pemuatan kelas:

Selepas menyediakan nilai awal pembolehubah kelas, mesin maya juga akan dimulakan

Atas 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!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam