Chapter sebelumnya memperlihatkan konversi otomatis dari tipe kecil ke tipe besar. Arah sebaliknya — memampatkan int ke byte, memotong double menjadi int, memangkas long menjadi int — tidak pernah diberlakukan otomatis karena informasi dapat tertinggal. Java meminta kita menyatakan niat tersebut secara eksplisit lewat type cast: penulisan tipe tujuan dalam tanda kurung sebelum nilai, misalnya (byte) nilai. Pada Chapter ini kita bedah cara kerja cast narrowing, membedah bit yang tersisa setelah pemotongan, dan melihat mengapa double ke int memotong bukan membulatkan.

Operator Cast #

Bentuk umum cast primitive adalah (TipeTujuan) ekspresi. Operator ini memerintahkan compiler: “saya tahu konversi ini berpotensi membuang data, dan saya menyetujuinya”. Compiler kemudian mengizinkan konversi narrowing yang sebelumnya ditolak. Tanggung jawab berpindah dari compiler ke kita — dan kesalahan rentang nilai tidak lagi terdeteksi saat kompilasi, melainkan berubah menjadi hasil yang salah secara diam-diam.

Dua mekanisme berbeda berlaku untuk dua kelompok tipe:

  • Integer ke integer yang lebih kecil (int → byte, long → int, dan sejenisnya): JVM memotong bit berlebih, hanya menyimpan bit tingkat rendah sebanyak kapasitas tipe tujuan. Nilai hasil bisa sama, bisa terpotong, bahkan berubah tanda.
  • Floating-point ke integer (double/float → int/long): JVM membuang bagian pecahan (mengarah ke nol). Angka 72.99 menjadi 72, bukan 73; angka -3.7 menjadi -3, bukan -4.

Memampatkan Integer #

Program berikut menguji enam konversi narrowing sekaligus — dua di antaranya menghasilkan kejutan:

public class CastingMenyempit {
    public static void main(String[] args) {
        int nilai130 = 130;
        byte sebagaiByte = (byte) nilai130;
        System.out.println("int 130     -> byte  : " + sebagaiByte);

        int nilai300 = 300;
        byte byte300 = (byte) nilai300;
        System.out.println("int 300     -> byte  : " + byte300);

        double berat = 72.99;
        int beratBulat = (int) berat;
        System.out.println("double 72.99-> int   : " + beratBulat);

        double suhu = -3.7;
        int suhuBulat = (int) suhu;
        System.out.println("double -3.7 -> int   : " + suhuBulat);

        long besar = 100_000_000_000L;
        int potong = (int) besar;
        System.out.println("long 1e11   -> int   : " + potong);

        char huruf = 'A';
        byte kode = (byte) huruf;
        System.out.println("char 'A'    -> byte  : " + kode);
    }
}

Output yang Dihasilkan:

text
int 130     -> byte  : -126
int 300     -> byte  : 44
double 72.99-> int   : 72
double -3.7 -> int   : -3
long 1e11   -> int   : 1215752192
char 'A'    -> byte  : 65

Mari kita bedah kasus-kasusnya satu per satu:

  1. Baris 4-5 ((byte) nilai130 → -126): angka 130 binernya 10000010 — delapan bit penuh. Karena byte berkapasitas delapan bit bertanda, bit tertinggi diperlakukan sebagai bit tanda: pola dua-komplemen 10000010 dibaca sebagai -126. Nilai asal hanya 3 unit di luar rentang byte (maksimum 127), tetapi hasilnya sudah melompat jauh ke ranah negatif.
  2. Baris 8-9 ((byte) nilai300 → 44): 300 binernya 100101100 (sembilan bit). byte menyimpan delapan bit terakhir 00101100 = 44; bit kesembilan yang bernilai 256 dibuang begitu saja.
  3. Baris 11-12 dan 14-15 ((int) berat dan (int) suhu): cast floating-point membuang pecahan ke arah nol — 72.99 turun ke 72, dan -3.7 naik ke -3. Tidak ada pembulatan ke terdekat.
  4. Baris 17-18 ((int) besar → 1215752192): 100000000000 butuh 37 bit; int hanya menyimpan 32 bit terbawah. Bit-bit tinggi yang memuat sebagian besar nilai hilang, menyisakan 1215752192 — angka yang tampak sah padahal salah total.
  5. Baris 20-21 ((byte) huruf → 65): konversi char ke byte hanya aman bila kode Unicode karakternya di bawah 128. Karakter 'A' (kode 65) selamat, tetapi karakter seperti 'é' (kode 233) berubah menjadi -23 karena rentang byte bertanda hanya sampai 127.

Membulatkan dengan Sadar #

Kalau tujuan kita membulatkan ke bilangan bulat terdekat — bukan sekadar membuang pecahan — cast adalah alat yang salah. Method Math.round() mengerjakan pembulatan ke terdekat, dan hasilnya berbeda terutama untuk angka negatif:

java Bulatkan.java
public class Bulatkan {
    public static void main(String[] args) {
        double harga = 72.99;
        System.out.println("cast   : " + (int) harga);
        System.out.println("round  : " + Math.round(harga));

        double suhu = -3.7;
        System.out.println("cast   : " + (int) suhu);
        System.out.println("round  : " + Math.round(suhu));
    }
}

Output yang Dihasilkan:

text
cast   : 72
round  : 73
cast   : -3
round  : -4

Dua pasangan hasil pada keluaran tersebut menegaskan bedanya: untuk 72.99, cast menghasilkan 72 sedangkan Math.round menghasilkan 73; untuk -3.7, cast menghasilkan -3 sedangkan Math.round menghasilkan -4 (pembulatan ke terdekat, yang untuk negatif berarti menjauh dari nol). Pilih alat sesuai maksud: cast untuk pemotongan, Math.round untuk pembulatan.

Cast Wajib, Bukan Opsional #

Bagaimana bila kita lupa menulis cast? Compiler menolak langsung, dan pesannya menyebut alasan persisnya:

public class ByteTanpaCast {
    public static void main(String[] args) {
        int populasiDesa = 7800;
        byte stokGudang = populasiDesa;
        System.out.println(stokGudang);
    }
}

Compiler javac menolak dengan error: incompatible types: possible lossy conversion from int to byte. Kata kuncinya possible: compiler tidak menganalisis isi variabel saat runtime — variabel int dapat berubah menjadi nilai berapa pun, termasuk yang melampaui byte, sehingga seluruh assignment int ke byte ditolak tanpa kecuali. Pengecualian hanya berlaku untuk literal langsung yang nilainya terverifikasi muat saat kompilasi — ingat byte umurBulan = 25; pada Chapter Primitive Data Types.

Kita kini memegang dua arah konversi: widening otomatis dan narrowing eksplisit. Namun ada satu wilayah konversi yang bekerja di balik layar pada hampir setiap operasi aritmetika: ketika byte dijumlah byte, atau int bertemu long, Java diam-diam mempromosikan operand ke tipe yang lebih besar sebelum menghitung. Aturan tersebut dinamai numeric promotion — dan sumber banyak kejutan — dibahas tuntas pada Chapter berikutnya.

Referensi #

Berkas Sumber

Berkas pendukung halaman ini dapat diunduh dan dijalankan langsung sesuai penjelasan di atas.

Bulatkan.java

Unduh berkas
java
public class Bulatkan {
    public static void main(String[] args) {
        double harga = 72.99;
        System.out.println("cast   : " + (int) harga);
        System.out.println("round  : " + Math.round(harga));

        double suhu = -3.7;
        System.out.println("cast   : " + (int) suhu);
        System.out.println("round  : " + Math.round(suhu));
    }
}

ByteTanpaCast.java

Unduh berkas
java
public class ByteTanpaCast {
    public static void main(String[] args) {
        int populasiDesa = 7800;
        byte stokGudang = populasiDesa;
        System.out.println(stokGudang);
    }
}

CastingMenyempit.java

Unduh berkas
java
public class CastingMenyempit {
    public static void main(String[] args) {
        int nilai130 = 130;
        byte sebagaiByte = (byte) nilai130;
        System.out.println("int 130     -> byte  : " + sebagaiByte);

        int nilai300 = 300;
        byte byte300 = (byte) nilai300;
        System.out.println("int 300     -> byte  : " + byte300);

        double berat = 72.99;
        int beratBulat = (int) berat;
        System.out.println("double 72.99-> int   : " + beratBulat);

        double suhu = -3.7;
        int suhuBulat = (int) suhu;
        System.out.println("double -3.7 -> int   : " + suhuBulat);

        long besar = 100_000_000_000L;
        int potong = (int) besar;
        System.out.println("long 1e11   -> int   : " + potong);

        char huruf = 'A';
        byte kode = (byte) huruf;
        System.out.println("char 'A'    -> byte  : " + kode);
    }
}