Saat proyek dikompilasi, hasilnya berupa pohon direktori .class yang dalam — kelas/com/toko/produk/Produk.class dan seterusnya. Membagikan pohon itu ke pengguna atau rekan tim berarti menyalin ratusan berkas kecil yang rawan terpotong path-nya. Java menuntaskannya dengan JAR (Java Archive) — satu berkas yang membungkus seluruh struktur direktori class beserta resources tambahan. Pada Chapter ini kita akan membedah isi JAR, membuatnya dengan tool jar, menjalankan aplikasi ber-JAR, dan memakai JAR library lewat classpath.
JAR sebagai Arsip ZIP #
Secara format, JAR adalah berkas ZIP biasa yang mengikuti struktur direktori package. Anda bisa membuktikannya sendiri: berkas .jar dapat dibuka dengan tool ZIP mana pun. Yang membedakannya dari ZIP polos adalah direktori khusus META-INF/ di akarnya, terutama berkas manifest (META-INF/MANIFEST.MF) yang menyimpan metadata arsip — di antaranya entry Main-Class yang menandai class titik masuk aplikasi.
Kita akan memakai dua class kecil sepanjang chapter ini — aplikasi sapaan dan class utilitas pendampingnya:
public class UtilMath {
public static int kuadrat(int n) {
return n * n;
}
}public class SapaanApp {
public static void main(String[] args) {
String nama = args.length > 0 ? args[0] : "Budi";
int kuadrat = UtilMath.kuadrat(nama.length());
System.out.println("Halo, " + nama + "!");
System.out.println("Panjang nama dikuadratkan: " + kuadrat);
}
}Output yang Dihasilkan:
Halo, Budi!
Panjang nama dikuadratkan: 16Programnya sederhana, tetapi dua class ini cukup untuk mendemonstrasikan seluruh siklus hidup JAR — dari kompilasi hingga distribusi.
Membuat dan Menjalankan JAR Aplikasi #
Alurnya tiga langkah: kompilasi, bungkus dengan jar --create, lalu jalankan. Perintah berikut kita jalankan sungguhan di direktori kerja yang memuat kedua class di atas:
javac SapaanApp.java UtilMath.java
jar --create --main-class=SapaanApp --file sapaan-app.jar SapaanApp.class UtilMath.class
java -jar sapaan-app.jar SitiOutput yang Dihasilkan:
Halo, Siti!Mari kita bedah perintah dan hasilnya:
javac SapaanApp.java UtilMath.java: mengompilasi kedua berkas menjadiSapaanApp.classdanUtilMath.classdi direktori kerja.jar --create --main-class=SapaanApp --file sapaan-app.jar ...: tooljarmembuat arsipsapaan-app.jarberisi kedua berkas.class; opsi--main-classmenuliskan entryMain-Class: SapaanAppke manifest sehingga JAR tahu titik masuknya.java -jar sapaan-app.jar Siti: launcher membaca manifest, mencariMain-Class, memuatSapaanApp, dan mengalirkan argumenSitikeargs— perhatikan sapaan menyapa Siti, bukan nilai bawaan Budi.
Isi manifest-nya bisa kita lihat langsung dengan mengekstrak berkasnya dari arsip:
unzip -p sapaan-app.jar META-INF/MANIFEST.MFOutput yang Dihasilkan:
Manifest-Version: 1.0
Created-By: 25.0.4.1 (Eclipse Adoptium)
Main-Class: SapaanAppTiga baris itu seluruh mekanisme di balik java -jar: versi manifest, pembuat arsip, dan nama class utama. Baris manifest ditutup dengan carriage return + line feed khas format ini, dan berkas selalu diakhiri satu baris kosong.
JAR Library di Classpath #
JAR tanpa Main-Class berperan sebagai library: kumpulan class untuk dipakai program lain. Launcher tetap memerlukannya melalui opsi classpath -cp. Mari bungkus ulang kedua class tanpa opsi main, lalu jalankan class dari dalamnya:
jar --create --file sapaan.jar SapaanApp.class UtilMath.class
java -cp sapaan.jar SapaanApp DewiOutput yang Dihasilkan:
Halo, Dewi!Opsi -cp sapaan.jar menyuruh JVM mencari class di dalam arsip — launcher menemukan SapaanApp di entry SapaanApp.class, memuatnya, dan menjalankan main. Inilah cara klasik mendistribusikan library ke pengguna: satu berkas JAR yang ditambahkan ke classpath proyek mereka. Bila class yang kita bungkus ber-package, struktur direktorinya ikut terbawa — com/toko/produk/Produk.class tersimpan di dalam JAR persis seperti struktur hasil javac -d.
Memeriksa Isi dengan jar –list #
Sebelum memakai JAR dari orang lain, sering kita perlu tahu isinya. Opsi --list (bentuk pendeknya jar tf) mencetak seluruh entry arsip:
jar --list --file sapaan-app.jarOutput yang Dihasilkan:
META-INF/
META-INF/MANIFEST.MF
SapaanApp.class
UtilMath.classDaftar ini memperlihatkan anatomi JAR secara utuh: direktori META-INF/ dengan manifest-nya diikuti berkas class di akar arsip — sesuai class tanpa package. JAR ber-package akan menampilkan entry seperti com/toko/produk/Produk.class. Pemeriksaan semacam ini menjawab banyak kasus “class tidak ditemukan” karena kita bisa memastikan class yang dicari memang ada di dalam arsip, dengan path yang persis sama dengan nama package-nya.
Kita kini punya satu berkas yang rapi untuk dibagikan. Namun classpath sendiri menyimpan masalah lama: dua JAR membawa class bernama sama, versi yang bertabrakan, dan tidak ada cara tahu dependensi apa saja yang sebenarnya dibutuhkan JAR milik orang lain. Ketidakpastian inilah yang memicu lahirnya Java Module System — topik Chapter berikutnya.
Referensi #
Berkas Sumber
Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.
SapaanApp.java
Unduh berkaspublic class SapaanApp {
public static void main(String[] args) {
String nama = args.length > 0 ? args[0] : "Budi";
int kuadrat = UtilMath.kuadrat(nama.length());
System.out.println("Halo, " + nama + "!");
System.out.println("Panjang nama dikuadratkan: " + kuadrat);
}
}
UtilMath.java
Unduh berkaspublic class UtilMath {
public static int kuadrat(int n) {
return n * n;
}
}