Mari kita mulai dengan dua kelas sederhana:
package com.michaelt.so.supers;
public class Sup {
int methodA(int a, int b) {
return a + b;
}
}
lalu
package com.michaelt.so.supers;
public class Sub extends Sup {
@Override
int methodA(int a, int b) {
return super.methodA(a, b);
}
}
Mengkompilasi methodA dan melihat kode byte yang didapat:
methodA(II)I
L0
LINENUMBER 6 L0
ALOAD 0
ILOAD 1
ILOAD 2
INVOKESPECIAL com/michaelt/so/supers/Sup.methodA (II)I
IRETURN
L1
LOCALVARIABLE this Lcom/michaelt/so/supers/Sub; L0 L1 0
LOCALVARIABLE a I L0 L1 1
LOCALVARIABLE b I L0 L1 2
MAXSTACK = 3
MAXLOCALS = 3
Dan Anda dapat melihat di sana dengan metode invokes khusus yang melakukan pencarian terhadap metode kelas Sup A ().
The invokespecial opcode memiliki logika berikut:
- Jika C berisi deklarasi untuk metode instance dengan nama dan deskriptor yang sama dengan metode yang diselesaikan, maka metode ini akan dipanggil. Prosedur pencarian berakhir.
- Kalau tidak, jika C memiliki superclass, prosedur pencarian yang sama ini dilakukan secara rekursif menggunakan superclass langsung dari C. Metode yang akan dipanggil adalah hasil dari doa rekursif dari prosedur pencarian ini.
- Kalau tidak, AbstractMethodError dinaikkan.
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.