Array tidak terbatas menyimpan angka — justru pemanfaatan paling umumnya adalah menampung sekumpulan objek: daftar siswa, katalog produk, atau antrean pesanan. Mekanismenya perlu dipahami dengan tepat: elemen array bertipe objek menyimpan referensi, bukan objeknya sendiri. Akibatnya ada dua langkah pembuatan — membuat array untuk menampung referensi, lalu membuat objek satu per satu untuk tiap slot. Chapter ini membedah kedua langkah tersebut beserta kesalahan NullPointerException yang muncul bila salah satu langkah terlewat.

Membuat Array Berisi Referensi #

Perhatikan perbedaan penting antara new Siswa[3] dan new Siswa(). Ekspresi pertama membuat array berisi tiga slot referensi yang seluruhnya diisi null — belum ada satu pun objek Siswa di dalamnya. Ekspresi kedua membuat satu objek Siswa di heap. Array berisi objek selalu membutuhkan dua tahap tersebut: slot disiapkan dulu, objek diisi kemudian.

Bentuk ringkasnya pun tersedia: array initializer bekerja untuk objek juga, misalnya Siswa[] kelas = {new Siswa("Budi", 85), new Siswa("Siti", 92)}; — compiler menghitung jumlah elemen dari jumlah ekspresi new di dalam kurung kurawal. Ukuran array tetap beku setelah dibuat; menambah siswa berarti membuat array baru dan menyalin isinya, persis mekanisme Chapter Array Copying.

java ArrayObjek.java
import java.util.Arrays;

class Siswa {
    String nama;
    int nilai;

    Siswa(String nama, int nilai) {
        this.nama = nama;
        this.nilai = nilai;
    }

    @Override
    public String toString() {
        return nama + "(" + nilai + ")";
    }
}

public class ArrayObjek {
    public static void main(String[] args) {
        Siswa[] kelas = new Siswa[3];
        System.out.println("Array baru    : " + Arrays.toString(kelas));

        kelas[0] = new Siswa("Budi", 85);
        kelas[1] = new Siswa("Siti", 92);
        kelas[2] = new Siswa("Dewi", 78);
        System.out.println("Setelah diisi : " + Arrays.toString(kelas));

        int total = 0;
        for (Siswa s : kelas) {
            total += s.nilai;
        }
        System.out.println("Rata-rata     : " + (total / kelas.length));
    }
}

Output yang Dihasilkan:

text
Array baru    : [null, null, null]
Setelah diisi : [Budi(85), Siti(92), Dewi(78)]
Rata-rata     : 85

Mari kita telaah baris-baris kode di atas:

  1. Baris 3-18 (class Siswa): class sederhana dengan dua field, constructor, dan toString yang menampilkan format nama(nilai) — agar Arrays.toString mencetak isi yang berarti, bukan penanda internal objek.
  2. Baris 22 (Siswa[] kelas = new Siswa[3];): membuat array tiga slot referensi. Output “Array baru” menunjukkan [null, null, null] — belum ada objek Siswa yang dibuat, hanya tempatnya yang tersedia.
  3. Baris 26-28 (kelas[0] = new Siswa("Budi", 85); dst.): tahap kedua — constructor dipanggil tiga kali, menghasilkan tiga objek terpisah di heap, lalu referensinya disimpan ke slot masing-masing.
  4. Baris 31-33 (perulangan for): variabel s berganti-ganti menampung referensi tiap elemen. Field s.nilai dibaca langsung dari objek yang dirujuk, menghasilkan total 255 dan rata-rata 85.

Membaca Field dari Slot yang Masih null #

Kesalahan klasiknya: mengakses member objek pada slot yang belum diisi. Compiler javac tidak bisa menolak daftar[0].nama karena tipe daftar[0] memang Peserta dan field nama sah — baris kode tersebut lolos pemeriksaan kompilasi. Baru saat program berjalan, JVM menemukan referensi bernilai null dan melempar NullPointerException.

java ObjekNull.java
class Peserta {
    String nama;
}

public class ObjekNull {
    public static void main(String[] args) {
        Peserta[] daftar = new Peserta[2];
        System.out.println("Membaca daftar[0].nama...");
        System.out.println(daftar[0].nama);
    }
}

Program di atas gagal dengan pesan persis berikut pada jalur keluar (exit code 1):

text
Exception in thread "main" java.lang.NullPointerException: Cannot read field "nama" because "<local1>[0]" is null
        at ObjekNull.main(ObjekNull.java:9)

Pesan tersebut menyebutkan persis apa yang terjadi: membaca field nama gagal karena elemen [0] dari array lokal bernilai null. Solusinya bukan menghindari array of objects, melainkan memastikan objek dibuat sebelum slotnya dipakai — isi dengan new per elemen seperti contoh pertama, atau periksa if (daftar[0] != null) bila memang ada slot yang sengaja kosong.

Perlu dicatat juga bahwa dua elemen array bisa menunjuk objek yang sama: kelas[1] = kelas[0] tidak menduplikasi objek Siswa, hanya menyamakan referensinya — pola referensi yang sama persis dengan Chapter Array Copying. Dengan bekal array dan objek ini, kita berpindah ke struktur data tekstual: String, tipe yang paling sering kita olah sehari-hari di Java.

Referensi #

Berkas Sumber

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

ArrayObjek.java

Unduh berkas
java
import java.util.Arrays;

class Siswa {
    String nama;
    int nilai;

    Siswa(String nama, int nilai) {
        this.nama = nama;
        this.nilai = nilai;
    }

    @Override
    public String toString() {
        return nama + "(" + nilai + ")";
    }
}

public class ArrayObjek {
    public static void main(String[] args) {
        Siswa[] kelas = new Siswa[3];
        System.out.println("Array baru    : " + Arrays.toString(kelas));

        kelas[0] = new Siswa("Budi", 85);
        kelas[1] = new Siswa("Siti", 92);
        kelas[2] = new Siswa("Dewi", 78);
        System.out.println("Setelah diisi : " + Arrays.toString(kelas));

        int total = 0;
        for (Siswa s : kelas) {
            total += s.nilai;
        }
        System.out.println("Rata-rata     : " + (total / kelas.length));
    }
}

ObjekNull.java

Unduh berkas
java
class Peserta {
    String nama;
}

public class ObjekNull {
    public static void main(String[] args) {
        Peserta[] daftar = new Peserta[2];
        System.out.println("Membaca daftar[0].nama...");
        System.out.println(daftar[0].nama);
    }
}