Nah untuk memahami bagaimana mengikat statis dan dinamis sebenarnya bekerja? atau bagaimana mereka diidentifikasi oleh compiler dan JVM?
Mari kita ambil contoh di bawah ini di mana Mammal
kelas induk yang memiliki metode speak()
dan Human
kelas diperpanjang Mammal
, mengganti speak()
metode dan kemudian membebani lagi dengan speak(String language)
.
public class OverridingInternalExample {
private static class Mammal {
public void speak() { System.out.println("ohlllalalalalalaoaoaoa"); }
}
private static class Human extends Mammal {
@Override
public void speak() { System.out.println("Hello"); }
// Valid overload of speak
public void speak(String language) {
if (language.equals("Hindi")) System.out.println("Namaste");
else System.out.println("Hello");
}
@Override
public String toString() { return "Human Class"; }
}
// Code below contains the output and bytecode of the method calls
public static void main(String[] args) {
Mammal anyMammal = new Mammal();
anyMammal.speak(); // Output - ohlllalalalalalaoaoaoa
// 10: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Mammal humanMammal = new Human();
humanMammal.speak(); // Output - Hello
// 23: invokevirtual #4 // Method org/programming/mitra/exercises/OverridingInternalExample$Mammal.speak:()V
Human human = new Human();
human.speak(); // Output - Hello
// 36: invokevirtual #7 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:()V
human.speak("Hindi"); // Output - Namaste
// 42: invokevirtual #9 // Method org/programming/mitra/exercises/OverridingInternalExample$Human.speak:(Ljava/lang/String;)V
}
}
Ketika kita mengkompilasi kode di atas dan mencoba untuk melihat bytecode yang digunakan javap -verbose OverridingInternalExample
, kita dapat melihat bahwa compiler menghasilkan tabel konstan di mana ia memberikan kode integer ke setiap panggilan metode dan kode byte untuk program yang telah saya ekstrak dan dimasukkan dalam program itu sendiri ( lihat komentar di bawah setiap panggilan metode)
Dengan melihat kode di atas kita dapat melihat bahwa bytecode dari humanMammal.speak()
, human.speak()
dan human.speak("Hindi")
sama sekali berbeda ( invokevirtual #4
, invokevirtual #7
, invokevirtual #9
) karena compiler mampu membedakan antara mereka berdasarkan daftar argumen dan referensi kelas. Karena semua ini diselesaikan pada waktu kompilasi secara statis, itulah sebabnya Overloading Metode dikenal sebagai Polimorfisme Statis atau Binding Statis. .
Tetapi bytecode for anyMammal.speak()
and humanMammal.speak()
is same ( invokevirtual #4
) karena menurut kompiler kedua metode dipanggilMammal
referensi.
Jadi sekarang pertanyaannya muncul jika kedua pemanggilan metode memiliki bytecode yang sama lalu bagaimana JVM mengetahui metode mana yang harus dipanggil?
Jawabannya tersembunyi di bytecode itu sendiri dan itu adalah invokevirtual
set instruksi. JVM menggunakaninvokevirtual
instruksi untuk memanggil Java yang setara dengan metode virtual C ++. Di C ++ jika kita ingin mengganti satu metode di kelas lain, kita perlu mendeklarasikannya sebagai virtual, Tetapi di Java, semua metode adalah virtual secara default karena kita dapat mengganti setiap metode di kelas anak (kecuali metode privat, final dan statis).
Di Java, setiap variabel referensi memiliki dua pointer tersembunyi
- Sebuah pointer ke tabel yang menyimpan metode objek dan pointer ke objek Kelas. misal [berbicara (), berbicara (String) objek Kelas]
- Sebuah pointer ke memori yang dialokasikan di heap untuk data objek tersebut, misalnya nilai variabel instance.
Jadi semua referensi objek secara tidak langsung memiliki referensi ke tabel yang menampung semua referensi metode objek itu. Java telah meminjam konsep ini dari C ++ dan tabel ini dikenal sebagai tabel virtual (vtable).
Vtable adalah struktur seperti array yang menyimpan nama metode virtual dan referensinya pada indeks array. JVM hanya membuat satu vtabel per kelas saat memuat kelas ke dalam memori.
Jadi setiap kali JVM menemukan invokevirtual
set instruksi, ia memeriksa vtable kelas itu untuk referensi metode dan memanggil metode tertentu yang dalam kasus kami adalah metode dari objek bukan referensi.
Karena semua ini diselesaikan hanya pada saat runtime dan pada saat runtime JVM mengetahui metode mana yang akan dipanggil, itulah mengapa Metode Overriding dikenal sebagai Dynamic Polymorphism atau hanya Polymorphism atau Dynamic Binding .
Anda dapat membacanya lebih detail di artikel saya Bagaimana JVM Menangani Metode Overloading dan Overriding Secara Internal .