Kelas Sub
adalah subkelas dari kelas Sup
. Apa artinya itu secara praktis? Atau dengan kata lain, apa arti praktis dari "warisan"?
Opsi 1: Kode dari Sup sebenarnya disalin ke Sub. (seperti pada 'copy-paste', tetapi tanpa kode yang disalin secara visual terlihat di subclass).
Contoh: methodA()
adalah metode yang awalnya dalam Sup. Sub extends Sup, begitu methodA()
juga (secara virtual) disalin ke Sub Sekarang Sub memiliki nama metode methodA()
. Ini identik dengan Sup methodA()
di setiap baris kode, tetapi sepenuhnya milik Sub - dan tidak bergantung pada Sup atau terkait dengan Sup dengan cara apa pun.
Opsi 2: Kode dari Sup sebenarnya tidak disalin ke Sub. Itu masih hanya di superclass. Tetapi kode itu dapat diakses melalui subclass dan dapat digunakan oleh subclass.
Contoh: methodA()
adalah metode dalam Sup. Sub meluas Sup, jadi sekarang methodA()
bisa diakses melalui sub seperti: subInstance.methodA()
. Tapi itu benar-benar akan memanggil methodA()
superclass. Yang berarti methodA () akan beroperasi dalam konteks superclass, bahkan jika itu dipanggil oleh subclass.
Pertanyaan: Manakah dari dua opsi yang benar-benar berfungsi? Jika tidak ada satu pun dari mereka, tolong jelaskan bagaimana hal ini benar-benar bekerja
sumber
Jawaban:
Pilihan 2.
Bytecode direferensikan secara dinamis saat runtime: inilah sebabnya, misalnya, LinkageErrors terjadi.
Misalnya, anggap Anda mengkompilasi dua kelas:
Sekarang modifikasi dan kompilasi ulang kelas induk tanpa memodifikasi atau mengkompilasi ulang kelas anak :
Akhirnya, jalankan program yang menggunakan kelas anak. Anda akan menerima NoSuchMethodError :
sumber
Mari kita mulai dengan dua kelas sederhana:
lalu
Mengkompilasi methodA dan melihat kode byte yang didapat:
Dan Anda dapat melihat di sana dengan metode invokes khusus yang melakukan pencarian terhadap metode kelas Sup A ().
The invokespecial opcode memiliki logika berikut:
Dalam hal ini, tidak ada metode instan dengan nama dan deskripsi yang sama di kelasnya sehingga peluru pertama tidak akan ditembakkan. Namun peluru kedua akan - ada superclass dan itu memanggil methodA super.
Kompiler tidak memasukkan ini dan tidak ada salinan sumber Sup di kelas.
Namun ceritanya belum selesai. Ini hanyakode yang dikompilasi . Setelah kode mencapai JVM, HotSpot dapat terlibat.
Sayangnya, saya tidak tahu banyak tentang hal itu, jadi saya akan naik banding ke pihak berwenang mengenai masalah ini dan pergi ke Inlining di Jawa di mana dikatakan bahwa HotSpot dapat menyatukan metode (bahkan metode non-final).
Pergi ke dokumen dicatat bahwa jika pemanggilan metode tertentu menjadi hot spot alih-alih melakukan pencarian setiap kali, informasi ini dapat digarisbawahi - secara efektif menyalin kode dari Sup methodA () ke Sub methodA ().
Ini dilakukan saat runtime, dalam memori, berdasarkan pada bagaimana aplikasi berperilaku dan optimasi apa yang diperlukan untuk mempercepat kinerja.
Seperti yang dinyatakan dalam HotSpot Internals for OpenJDK "Metode sering kali digarisbawahi. Doa statis, pribadi, final, dan / atau" khusus "mudah untuk diselaraskan."
Jika Anda menggali opsi untuk JVM Anda akan menemukan opsi
-XX:MaxInlineSize=35
(35 sebagai default) yang merupakan jumlah maksimum byte yang dapat digariskan. Saya akan menunjukkan bahwa inilah mengapa Java suka memiliki banyak metode kecil - karena mereka dapat dengan mudah diuraikan. Metode-metode kecil menjadi lebih cepat ketika mereka dipanggil lebih karena mereka dapat digarisbawahi. Dan sementara seseorang dapat bermain dengan angka itu dan membuatnya lebih besar itu dapat menyebabkan optimasi lainnya menjadi kurang efektif. (Pertanyaan SO terkait: Strategi inline HotSpot JIT yang menunjukkan sejumlah opsi lain untuk mengintip internal inlining yang sedang dilakukan HotSpot).Jadi, tidak - kode tidak diuraikan pada waktu kompilasi. Dan, ya - kode tersebut dapat diuraikan dengan baik pada saat runtime jika optimasi kinerja memerlukannya.
Dan semua yang saya tulis tentang HotSpot inlining hanya berlaku untuk HotSpot JVM yang didistribusikan oleh Oracle. Jika Anda melihat daftar mesin virtual Java wikipedia ada banyak lebih dari sekadar HotSpot dan cara mereka menangani inline JVM bisa sangat berbeda dari apa yang saya jelaskan di atas. Apache Harmony, Dalvik, ART - semuanya dapat bekerja secara berbeda di sana.
sumber
kode tidak disalin, diakses dengan referensi:
kompiler dapat mengoptimalkan bagaimana ini diwakili / dieksekusi dalam memori, tapi itu pada dasarnya struktur
sumber