Apa perbedaan antara waktu kompilasi dan dependensi run time di Java? Ini terkait dengan jalur kelas, tetapi apa perbedaannya?
Jawaban:
Ketergantungan waktu kompilasi : Anda memerlukan ketergantungan di Anda CLASSPATH
untuk mengompilasi artefak Anda. Mereka dibuat karena Anda memiliki semacam "referensi" ke dependensi yang di-hardcode dalam kode Anda, seperti memanggil new
beberapa kelas, memperluas atau mengimplementasikan sesuatu (baik secara langsung atau tidak langsung), atau pemanggilan metode menggunakan reference.method()
notasi langsung .
Ketergantungan run-time : Anda membutuhkan ketergantungan di Anda CLASSPATH
untuk menjalankan artefak Anda. Mereka diproduksi karena Anda menjalankan kode yang mengakses dependensi (baik dengan cara hardcode atau melalui refleksi atau apa pun).
Meskipun ketergantungan waktu kompilasi biasanya menyiratkan ketergantungan waktu proses, Anda dapat memiliki ketergantungan hanya waktu kompilasi. Hal ini didasarkan pada fakta bahwa Java hanya menautkan dependensi kelas pada akses pertama ke kelas tersebut, jadi jika Anda tidak pernah mengakses kelas tertentu pada waktu proses karena jalur kode tidak pernah dilalui, Java akan mengabaikan kelas dan dependensinya.
Contoh ini
Dalam C. java (menghasilkan C.class):
package dependencies;
public class C { }
Dalam A. java (menghasilkan kelas A.):
package dependencies;
public class A {
public static class B {
public String toString() {
C c = new C();
return c.toString();
}
}
public static void main(String[] args) {
if (args.length > 0) {
B b = new B();
System.out.println(b.toString());
}
}
}
Dalam kasus ini, A
memiliki ketergantungan waktu kompilasi pada C
through B
, tetapi itu hanya akan memiliki ketergantungan waktu proses pada C jika Anda melewatkan beberapa parameter saat mengeksekusi java dependencies.A
, karena JVM hanya akan mencoba untuk menyelesaikan B
ketergantungan pada C
saat itu akan dieksekusi B b = new B()
. Fitur ini memungkinkan Anda untuk menyediakan pada waktu proses hanya dependensi class yang Anda gunakan di jalur kode, dan mengabaikan dependensi class lainnya dalam artefak.
Contoh mudahnya adalah dengan melihat api seperti servlet api. Untuk membuat servlet Anda dikompilasi, Anda memerlukan servlet-api.jar, tetapi pada saat runtime container servlet menyediakan implementasi servlet api sehingga Anda tidak perlu menambahkan servlet-api.jar ke jalur kelas runtime Anda.
Kompiler memerlukan classpath yang benar untuk mengompilasi panggilan ke perpustakaan (mengompilasi dependensi waktu)
JVM memerlukan jalur kelas yang benar untuk memuat kelas di perpustakaan yang Anda panggil (dependensi waktu proses).
Mereka mungkin berbeda dalam beberapa hal:
1) jika kelas C1 Anda memanggil kelas perpustakaan L1, dan L1 memanggil kelas perpustakaan L2, maka C1 memiliki ketergantungan waktu proses pada L1 dan L2, tetapi hanya ketergantungan waktu kompilasi pada L1.
2) jika kelas C1 Anda secara dinamis membuat instance antarmuka I1 menggunakan Class.forName () atau mekanisme lain, dan kelas implementasi untuk antarmuka I1 adalah kelas L1, maka C1 memiliki ketergantungan waktu proses pada I1 dan L1, tetapi hanya ketergantungan waktu kompilasi di I1.
Dependensi "tidak langsung" lainnya yang sama untuk waktu kompilasi dan waktu proses:
3) kelas C1 Anda memperluas kelas perpustakaan L1, dan L1 mengimplementasikan antarmuka I1 dan memperluas kelas perpustakaan L2: C1 memiliki ketergantungan waktu kompilasi pada L1, L2, dan I1.
4) kelas C1 Anda memiliki metode foo(I1 i1)
dan metode di bar(L1 l1)
mana I1 adalah antarmuka dan L1 adalah kelas yang mengambil parameter yaitu antarmuka I1: C1 memiliki ketergantungan waktu kompilasi pada I1 dan L1.
Pada dasarnya, untuk melakukan sesuatu yang menarik, kelas Anda perlu berinteraksi dengan kelas dan antarmuka lain di classpath. Grafik kelas / antarmuka yang dibentuk oleh kumpulan antarmuka perpustakaan tersebut menghasilkan rantai ketergantungan waktu kompilasi. Implementasi library menghasilkan rantai dependensi run-time. Perhatikan bahwa rantai ketergantungan waktu proses bergantung pada waktu proses atau gagal-lambat: jika penerapan L1 terkadang bergantung pada pembuatan instance objek kelas L2, dan kelas tersebut hanya dibuat instance-nya dalam satu skenario tertentu, maka tidak ada ketergantungan kecuali di skenario itu.
Java sebenarnya tidak menautkan apa pun pada waktu kompilasi. Ini hanya memverifikasi sintaks menggunakan kelas yang cocok yang ditemukannya di CLASSPATH. Tidak sampai waktu proses semuanya disatukan dan dijalankan berdasarkan CLASSPATH pada saat itu.
Dependensi waktu kompilasi hanyalah dependensi (kelas lain) yang Anda gunakan secara langsung di kelas yang Anda kompilasi. Dependensi waktu proses mencakup dependensi langsung dan tidak langsung dari kelas yang Anda jalankan. Jadi, dependensi waktu proses menyertakan dependensi dependensi dan dependensi refleksi apa pun seperti nama kelas yang Anda miliki di String
, tetapi digunakan di Class#forName()
.
A
, B.jar dengan B extends A
dan C.jar dengan C extends B
maka C.jar tergantung waktu kompilasi pada A.jar meskipun ketergantungan C pada A tidak langsung.
Untuk Java, ketergantungan waktu kompilasi adalah ketergantungan kode sumber Anda. Misalnya, jika kelas A memanggil metode dari kelas B, maka A bergantung ke B pada waktu kompilasi karena A harus mengetahui tentang B (tipe B) yang akan dikompilasi. Triknya di sini seharusnya seperti ini: Kode yang dikompilasi belum menjadi kode yang lengkap dan dapat dieksekusi. Ini termasuk alamat yang dapat diganti (simbol, metadata) untuk sumber yang belum dikompilasi atau ada di toples eksternal. Selama penautan, alamat tersebut harus diganti dengan alamat sebenarnya di memori. Untuk melakukannya dengan benar, simbol / alamat yang benar harus dibuat. Dan ini bisa dilakukan dengan tipe kelas (B). Saya yakin itulah ketergantungan utama pada waktu kompilasi.
Ketergantungan runtime lebih terkait dengan flow-of-control yang sebenarnya. Ini meminta alamat memori yang sebenarnya. Ini adalah ketergantungan yang Anda miliki saat program Anda berjalan. Anda memerlukan detail kelas B di sini seperti implementasi, bukan hanya info jenis. Jika kelas tidak ada, maka Anda akan mendapatkan RuntimeException dan JVM akan keluar.
Kedua dependensi, secara umum dan tidak seharusnya, mengalir ke arah yang sama. Ini adalah masalah desain OO.
Di C ++, kompilasi sedikit berbeda (tidak hanya dalam waktu) tetapi juga memiliki linker. Jadi prosesnya mungkin dianggap mirip dengan Java.