"Konstruktor dan Inisialisasi Objek"
Kelas pada Java memiliki sifat yang sama sekali berbeda dengan
tipe data primitif lainnya, seperti
int atau
boolean. Seperti
disebutkan pada bagian sebelumnya, mendeklarasikan suatu variabel
dengan tipe suatu kelas tidak berarti membuat objek dari kelas
tersebut. Objek tersebut harus dibuat (constructed). Pada saat objek dibuat, komputer akan mencari tempat yang tidak dipakai
pada memori heap untuk menempatkan objek tersebut, kemudian mengisi
objek itu dengan variabel instansi. Sebagai programmer, kita tidak
peduli dengan bagaimana suatu objek disimpan, akan tetapi kita ingin
mengatur supaya nilai yang disimpan pada saat objek tersebut dibuat
sesuai dengan keinginan kita. Dalam beberapa kasus, kita bahkan ingin
suatu objek melakukan tugas tertentu untuk pertama kali begitu ia
diciptakan.
Variabel instansi dapat diisi dengan nilai awal pada saat ia
dideklarasikan, seperti variabel lainnya. Misalnya, kelas berikut yang
bernama
PasanganDadu, yang melambangkan sepasang dadu. Kelas ini
memiliki dua variabel instansi yang melambangkan nilai yang ditunjukkan
oleh masing-masing dadu dan metode instansi untuk mengocok dadu, yaitu :
class PasanganDadu {
public int dadu1 = 3; // Angka pada dadu pertama
public int dadu2 = 4; // Angka pada dadu kedua
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int)(Math.random()*6) + 1;
dadu2 = (int)(Math.random()*6) + 1;
}
} // akhir kelas PasanganDadu
Variabel instansi
dadu1 dan
dadu2 diisi dengan nilai awal 3
dan 4. Inisialisasi ini dilakukan setiap kali objek
PasanganDadu
dibuat. Ingat bahwa kelas
PasanganDadu hanya 1, akan tetapi kita bisa
membuat banyak objek dari kelas ini. Setiap kali objek dibuat, objek
tersebut memiliki tempat di memori sendiri, yang disebut dengan
instansi objek tersebut. Perintah "
dadu1 = 3" dan "
dadu2 = 4" akan
dieksekusi setiap kali objek dibuat.
Kita bisa memodifikasi kelas PasanganDadu dengan nilai awal
acak, bukan 3 dan 4 misalnya, dengan potongan kode berikut :
class PasanganDadu {
public int dadu1 = (int)(Math.random()*6) + 1; // Angka pada dadu pertama
public int dadu2 = (int)(Math.random()*6) + 1; // Angka pada dadu kedua
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int)(Math.random()*6) + 1;
dadu2 = (int)(Math.random()*6) + 1;
}
} // akhir kelas PasanganDadu
Karena inisialisasi dilakukan setiap kali objek dibuat, maka
setiap objek akan memiliki nilai yang berbeda-beda hasil dari instruksi
Math.random() pada inisialisasi variabel instansi. Untuk inisialisasi
variabel static, hal ini tidak mungkin dilakukan, karena hanya ada 1
variabel statik untuk 1 kelas, tidak peduli berapa pun banyaknya objek
yang dibuat.
Jika variabel instansi tidak kita beri nilai awal, maka nilai
bawaan akan diberikan secara otomatis. Tipe data numerik (int, double,
dll) memiliki nilai bawaan 0; boolean bernilai awal false; dan char
bernilai awal karakter dengan kode Unicode 0. Variabel instansi juga
bisa bertipe suatu objek. Dalam hal ini, variabel tersebut bernilai
awal null. (Ingat bahwa String adalah objek, sehingga nilai awalnya
adalah null).
Objek dibuat dengan operator new, misalnya program yang ingin
menggunakan objek
PasanganDadu dapat menggunakan perintah berikut :
// deklarasi variabel dan pembuatan objek dilakukan sekaligus
PasanganDadu dadu = new PasanganDadu();
Pada contoh di atas,
new PasanganDadu() adalah perintah untuk
membuat objek, meletakkannya di memori dan menyimpan alamat objek ini
di memori pada variabel dadu. Bagian ekspresi
PasanganDadu() mirip
seperti memanggil subrutin. Sebetulnya itulah yang terjadi, yaitu
program memanggil subrutin spesial yang dinamakan konstruktor
(constructor). Mungkin Anda heran karena kita tidak melihat adanya
subrutin bernama
PasanganDadu(). Akan tetapi semua kelas memiliki
konstruktor, yang jika kita tidak buat secara khusus, Java akan
menambahkannya secara otomatis, yang disebut konstruktor bawaan.
Konstruktor bawaan melakukan hal-hal umum seperti mengalokasi
memori, mengisi nilai variabel instansi dengan nilai bawaannya, dan
mengembalikan alamat objek yang dibuat di memori. Jika kita
menginginkan hal lain yang ikut dilaksanakan ketika suatu objek dibuat,
maka kita harus membuat konstruktor sendiri.
Bagaimana cara mendefinisikan konstruktor? Konstruktor
dideklarasikan mirip dengan deklarasi subrutin, dengan 3 perkecualian.
Konstruktor tidak memiliki tipe keluaran (void pun tidak dibolehkan.
Namanya harus sama dengan nama kelas di mana ia dideklarasikan. Sifat
yang bisa digunakan hanya sifat akses, yaitu public, private, dan
protected (static tidak diperbolehkan).
Di lain pihak, konstruktor memiliki blok yang terdiri dari
kumpulan perintah seperti pada subrutin. Kita bisa menggunakan perintah
apapun seperti pada subrutin biasa, termasuk memiliki satu atau lebih
parameter formal. Sebetulnya salah satu alasan untuk menggunakan
parameter adalah kita bisa membuat beberapa konstruktor yang menerima
data dalam berbagai bentuk, sehingga objek yang kita buat bisa
dinisialisasi dengan cara yang berbeda-beda sesuai dengan kondisi dan
kebutuhan dari program yang akan kita buat.
Misalnya, kelas
PasanganDadu di atas kita ubah sehingga kita
bisa memberi nilai awal sendiri. Dalam hal ini kita buat konstruktor
yang menerima 2 nilai sebagai nilai awal dadu, yaitu nilai1 dan nilai2.
class PasanganDadu {
public int dadu1; // Angka pada dadu pertama
public int dadu2; // Angka pada dadu kedua
public PasanganDadu(int nilai1, int nilai2) {
// Konstruktor, mengambil nilai1 dan nilai2 sebagai nilai awal untuk dadu1 dan dadu2
dadu1 = nilai1;
dadu2 = nilai2;
}
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int)(Math.random()*6) + 1;
dadu2 = (int)(Math.random()*6) + 1;
}
} // akhir kelas PasanganDadu
Konstruktor dideklarasikan dalam bentuk "public
PasanganDadu(int nilai1, int nilai2) ...", tanpa tipe keluaran dan
dengan nama yang sama dengan nama kelas. Ini adalah cara Java mengenal
suatu konstruktor dan membedakannya dengan subrutin biasa. Konstruktor
ini memiliki 2 parameter yang harus diisi ketika konstruktor dipanggil.
Misalnya,
PasanganDadu dadu = new PasanganDadu(1,2);
Membuat objek baru yang variabel intansinya dadu1 dan dadu2
bernilai 1 dan 2.
Karena sekarang kita telah membuat konstruktor, kita
tidak
bisa lagi membuat objek dengan perintah "new PasanganDadu()". Java akan
membuat konstruktor bawaan apabila tidak ada satupun konstruktor yang
didefinisikan. Akan tetapi, kita bisa membuat konstruktor lain di kelas
tersebut, karena suatu kelas bisa terdiri dari beberapa konstruktor
asalkan parameternya berbeda.
Sekarang kita akan modifikasi lagi kelas tersebut dengan 2
konstruktor, yang mana apabila tidak ada parameter yang diberikan, maka
objek tersebut akan mengisi nilai dadu1 dan dadu2 dengan bilangan acak.
class PasanganDadu {
public int dadu1; // Angka pada dadu pertama
public int dadu2; // Angka pada dadu kedua
public PasanganDadu() {
// Isi dadu1 dan dadu2 dengan bilangan acak, dengan memanggil metode
// kocok()
kocok();
}
public PasanganDadu(int nilai1, int nilai2) {
// Konstruktor, mengambil nilai1 dan nilai2 sebagai nilai awal untuk
// dadu1 dan dadu2
dadu1 = nilai1;
dadu2 = nilai2;
}
public void kocok() {
// Kocok dadu dengan menggunakan bilangan acak antara 1 dan 6
dadu1 = (int) (Math.random() * 6) + 1;
dadu2 = (int) (Math.random() * 6) + 1;
}
} // akhir kelas PasanganDadu
Sekarang kita bisa memilih bagaimana membuat objek, yaitu
dengan "
new PasanganDadu()" atau dengan "
new PasanganDadu(x,y)", di
mana x dan y adalah ekpresi bernilai int.
Kelas ini, bisa digunakan dalam program lain yang membutuhkan
sepasang dadu. Program tersebut tidak lagi harus memanggil fungsi
(int)(Math.random()*6) + 1
karena perintah ini sudah diimplementasikan di dalam kelas
PasanganDadu. Bagi programmer, teknik seperti ini mempermudah pemecahan
masalah dengan mengelompokkannya menjadi ciri dan perilaku suatu objek.
Berikut ini adalah contoh program lain yang menggunakan objek
PasanganDadu() untuk menghitung berapa kali kocok akan menghasilkan
jumlah nilai yang sama. Program lengkapnya bisa
diunduh di sini untuk diimport ke dalam Eclipse.
public class KocokDuaPasangDadu {
/**
* @param args
*/
public static void main(String[] args) {
PasanganDadu daduPertama = new PasanganDadu(); // pasangan dadu pertama
PasanganDadu daduKedua = new PasanganDadu(); // pasangan dadu kedua
int jumlahKocokan; // untuk mengitung berapa kali dua pasang dadu
// tersebut dikocok
int total1; // hitung berapa kali dadu pertama muncul
int total2; // hitung berapa kali dadu kedua muncul
jumlahKocokan = 0;
do {
daduPertama.kocok(); // kocok dadu pertama
total1 = daduPertama.dadu1 + daduPertama.dadu2; // hitung jumlahnya
System.out.println("Pasangan dadu pertama berjumlah " + total1);
daduKedua.kocok(); // kocok dadu pertama
total2 = daduKedua.dadu1 + daduKedua.dadu2; // hitung jumlahnya
System.out.println("Pasangan dadu pertama berjumlah " + total2);
jumlahKocokan++;
System.out.println(); // cetak baris kosong
} while (total1 != total2);
System.out.println("Butuh " + jumlahKocokan
+ " kocokan hingga pasangan "
+ " dadu pertama dan kedua berjumlah sama");
}
}
Keluarannya adalah sebagai berikut

Konstruktor adalah subrutin, tetapi bukan subrutin biasa, dan
bukan metode instansi, karena konstruktor tidak dimiliki oleh suatu
objek. Karena tugasnya membuat objek, maka konstruktor dijalankan
sebelum objek dibuat. Konstruktor mirip dengan subrutin anggota statik,
tetapi dia tidak bisa dideklarasikan "static". Bahkan menurut
spesifikasi Java, konstruktor bukan anggota suatu kelas sama sekali.
Tidak seperti subrutin lain, konstruktor hanya bisa dipanggil
melalui operator "new", dalam bentuk
new nama_kelas(parameter);
di sini "parameter" boleh kosong. Hasil keluarannya adalah alamat
memori di mana objek yang baru dibuat tersebut disimpan. Seringkali,
kita akan simpan hasil keluarannya di dalam suatu variabel, atau bisa
juga hasil keluarannya diberikan ke dalam suatu fungsi sebagai
parameter.
Memanggil konstruktor lebih rumit daripada memanggil
subrutin atau fungsi biasa. Hal-hal berikut sangat membantu untuk lebih
memahami apa yang dilakukan oleh konstruktor ketika ia dipanggil untuk
membuat suatu objek:
- Pertama, komputer memberi daerah pada memori yang tidak digunakan, cukup untuk dipakai oleh objek yang akan dibuat
- Komputer
akan mengisi variabel instansi objek tersebut dengan nilai bawaannya.
Jika deklarasi variabel instansi pada kelas memiliki nilai awal
tertentu, maka nilai tersebut akan dimasukkan sebagai nilai awalnya.
- Parameter
aktual pada konstruktor (jika ada) akan dievaluasi dan nilainya
diberikan kepada parameter formal konstruktor tersebut.
- Perintah pada konstruktor (jika ada) akan dilaksanakan.
- Referensi objek akan dikembalikan kepada si pemanggil.
Hasil
keluarannya adalah referensi ke objek yang baru saja dibuat. Kita bisa
gunakan referensi ini untuk mengambil data pada variabel instansi objek
tersebut atau memanggil metode instansinya.
Contoh lain, mari kita ganti kelas
Murid pada
bagian sebelumnya. Kita akan tambahkan konstruktor dan juga kita ganti variabel instansi "
nama" menjadi bersifat privat.
class Murid {
private String nama; // Nama murid
public double nilai1, nilai2, nilai3; // Nilai-nilai ujian
Murid(String namaMurid) {
// Konstruktor objek Murid
nama = namaMurid;
}
public String getNama() {
// Metode untuk mengambil variabel anggota yang bersifat private
// misalnya variabel instansi nama
return nama;
}
public double hitungRataRata() {
// Hitung rata-rata ulangan
return (nilai1 + nilai2 + nilai3) / 3;
}
} // akhir kelas Murid
Objek bertipe Murid berisi informasi tentang murid tertentu. Konstruktor kelas ini memiliki parameter bertipe
String yaitu nama murid yang akan kita buat. Objek bertipe Murid ini bisa dibuat dengan pernyataan seperti:
mrd1 = new Murid("Ahmad Surahmat");
mrd2 = new Murid("Hamid Samsudin")
Pada versi aslinya, isi variabel
nama
harus diisi dengan perintah terpisah setelah objek dibuat. Masalahnya
programmer tidak selalu ingat untuk mengisi nilai nama. Pada versi baru
di atas, setiap kali kita membuat objek, parameter
namaMurid
harus disertakan, karena ini dideklarasikan pada konstruktornya. Dengan
demikian potensi bug karena kelalaian programmer dapat dihilangkan
dengan mudah.
Contoh keamanan lainnya adalah dengan membuat variabel instansi
nama
bersifat private. Ini berarti variabel ini tidak bisa diakses oleh
dunia luar secara langsung. Variabel ini hanya bisa diambil nilainya
dengan metode instansi
getNama,
dan karena tidak bisa diakses langsung dari luar, maka isi variabel ini
tidak bisa diganti dari luar kelas. Sekali objek Murid dibuat, maka
namanya tidak bisa diganti selama murid tersebut ada.