Showing posts with label tentang java.. Show all posts
Showing posts with label tentang java.. Show all posts

Wednesday

Pewarisan, Polimorfisme, dan Kelas Abstrak

Kelas melambangkan cetak biru objek yang memiliki kesamaan struktuk dan perilaku. Kelas menentukan struktur suatu objek melalui variabel yang terkandung dalam setiap objek, dan menentukan perilaku melalui metode instansi yang merupakan perilaku suatu objek.
Ide utama dari pemrograman berorientasi objek -- yang membedakannya dari pemrograman tradisional -- adalah menciptakan kelas yang memiliki hanya beberapa (tidak semua) struktur dan perilaku. Kemiripan ini diekspresikan dalam bentuk pewarisan dan polimorfisme (perubahan bentuk).
Istilah pewarisan berarti suatu kelas bisa mewariskan sebagian atau keseluruhan struktur dan perilaku kelas lain. Jika kelas B adalah kelas turunan dari kelas A, maka kita bisa juga menyebut kelas A adalah kelas super dari kelas B. Kelas turunan bisa memiliki struktur atau perilaku tambahan dari kelas supernya. Atau bahkan kelas turunan bisa mengubah atau mengganti perilaku kelas supernya. Hubungan antara kelas turunan dan kelas super sering dilukiskan dalam bentuk diagram di mana kelas turunan digambarkan di bawah kelas supernya, dan dihubungkan dengan garis penghubung dengan tanda segitiga yang diletakkan di dekat kelas supernya.
Dalam bahasa Java, ketika kita membuat suatu kelas, kita bisa menyatakan bahwa kelas tersebut merupakan kelas turunan dari kelas lain. Jika kita buat kelas yang bernama "B" dan kita ingin kelas ini menjadi kelas turunan dari kelas "A", kita akan tulis dalam bentuk :
class B extends A {
    .
    .  // tambahan atau perubahan
    .  // struktur dan perilaku dari kelas A
    .
}
Beberapa kelas dapat menurunkan kelas yang sama. Kelas-kelas turunan ini masing-masing disebut kelas saudara, yaitu diwariskan dari satu kelas super yang sama. Struktur dan perilaku kelas super ini akan dimiliki oleh masing-masing turunannya. Pada diagram berikut, kelas B, C, dan D adalah kelas saudara. Pewarisan juga bisa dilakukan beberapa kali, atau suatu kelas bisa memiliki cucu, buyut, dan seterusnya. Pada diagram, kelas E merupakan kelas turunan kelas D, sehingga kelas E adalah "cucu" dari kelas A. Kelas E masih bisa disebut turunan dari kelas A, walaupun bukan merupakan turunan langsungnya.
Mari kita buat sebuah contoh. Kita akan membuat program yang berhubungan dengan kendaraan bermotor, yang meliputi mobil, truk, dan motor. Program tersebut memiliki kelas yang dinamakan Kendaraan yang melambangkan semua  jenis kendaraan bermotor. Kelas Kendaraan memiliki variabel instansi seperti nomorPolisi dan pemilik dan metode instansi yang bernama gantiPemilik. Variabel dan metode instansi ini bisa digunakan oleh segala jenis kendaraan bermotor.
Ada 3 kelas turunannya yaitu Mobil, Truk dan Motor yang akan menyimpan variabel dan metode khusus untuk setiap jenis kendaraan. Kelas Mobil misalnya memiliki variabel jumlahPintu, kelas Truk memiliki variabel jumlahRoda, dan kelas Motor memiliki variabel jumlahTak. Kelas-kelas ini bisa dideklarasikan dalam Java dalam bentuk.
class Kendaraan {
    int nomorPolisi;
    Orang pemilik;  // (anggap kelas Orang telah dibuat sebelumnya)
    void gantiPemilik(Orang pemilikBaru) {
        . . .
    }
    . . .
}
 
class Mobil extends Kendaraan {
    int jumlahPintu;
    . . .
}
 
class Truk extends Kendaraan {
    int jumlahRoda;
    . . .
}
 
class Motor extends Kendaraan {
    int jumlahTak;  // 2-tak atau 4-tak
    . . .
}
Anggap mobilku adalah variabel dengan tipe Mobil akan dideklarasikan dan diinisialisasi dengan pernyataan berikut.
Mobil mobilku = new Mobil();
Dengan deklarasi seperti ini, maka program akan bisa mengakses mobilku.jumlahPintu, karena jumlahPintu adalah variabel instansi dari kelas Mobil. Akan tetapi karena kelas Mobil merupakan turunan dari kelas Kendaraan, maka mobil ini juga memiliki stuktur dan perilaku dari kendaraan. Artinya program juga bisa mengakses mobilku.nomorPolisi, mobilku.pemilik, dan menjalankan metode mobilku.gantiPemilik()
Dalam dunia nyata mobil, truk dan motor memang kendaraan (bukan hanya pada program). Dalam arti objek yang memiliki tipe Mobil atau Truk atau Motor juga secara otomatis objek bertipe Kendaraan. Fakta penting berikutnya :
Variabel yang dapat diisi referensi ke objek suatu kelas A juga dapat diisi referensi ke objek kelas turunan dari kelas A.
Efek praktis dari penyataan ini adalah, objek dengan tipe Mobil dapat diisi ke dalam variabel bertipe Kendaraan, atau dengan kata lain perintah berikut adalah valid.
Kendaraan kendaraanku = mobilku;
atau bahkan juga perintah berikut.
Kendaraan kendaraanku = new Mobil();
Setelah pernyataan di atas, variabel kendaraanku berisi referensi ke objek Kendaraan, yang kebetulan merupakan instansi dari kelas turunannya, yaitu kelas Mobil. Objek akan "mengingat" bahwa yang disimpan dalam variabel tersebut adalah objek bertipe Mobil, bukan Kendaraan. Informasi tentang objek apa yang disimpan pada memori ikut disertakan bersama objek tersebut, sehingga variabel yang bertipe Kendaraan akan tahu dengan pasti tipe objek yang dirujuknya. Kita juga dapat menguji jenis objek yang disimpan suatu variabel dengan menggunakan operator instanceof. Misalnya
if (kendaraanku instanceof Mobil) { ... }
menguji apakah objek yang dirujuk pada variabel kendaraanku merupakan objek bertipe Mobil.
Kebalikannya, pernyataan berikut tidak bisa dilakukan.
mobilku = kendaraanku;
karena kendaraanku bisa bertipe objek lain seperti Truk atau Motor. Apabila kita tahu persis bahwa kendaraanku bertipe Mobil, kita bisa menggunakan casting, untuk memberi tahu komputer untuk memperlakukan variabel kendaraanku memiliki tipe Mobil. Jadi kita bisa gunakan perintah.
mobilku = (Mobil)kendaraanku;
Atau kita juga bisa mengakses ((Mobil)kendaraanku).jumlahPintu. Mari kita gunakan kelas ini dalam program, dan kita ingin mencetak informasi yang sesuai dengan suatu kendaraan. Misalnya:
System.out.println("Data Kendaraan:");
System.out.println("Nomor polisi:  " + kendaraanku.nomorPolisi);
if (kendaraanku instanceof Mobil)
    System.out.println("Jenis kendaraan:  Mobil");
    Mobil m = (Mobil)kendaraanku;
    System.out.println("Jumlah pintu:  " + m.jumlahPintu);
}
else if (kendaraanku instanceof Truk) {
    System.out.println("Jenis kendaraan:  Truk");
    Truk t = (Truk)kendaraanku ;
    System.out.println("Jumlah roda:  " + t.jumlahRoda);
}
else if (kendaraanku instanceof Motor) {
    System.out.println("Jenis kendaraan:  Motor");
    Motor sm = (Motor)kendaraanku ;
    System.out.println("Jumlah tak:    " + sm.jumlahTak);
}
Lihat bahwa untuk setiap jenis objek, komputer akan menguji satu per satu tipe objek yang disimpan dalam kendaraanku. Jika kendaraanku[code] merujuk pada objek bertipe Truk maka casting [code](Mobil)kendaraanku akan menampilkan pesan kesalahan.


Contoh lain, mari kita buat program untuk menggambar suatu bentuk geometri pada layar. Misalnya bentuk geometri tersebut terdiri dari persegi panjang, oval, dan kotak bersudut lingkar dengan berbagai warna.
Kelas yang akan kita buat adalah PersegiPanjang, Oval, dan KotakLingkar. Ketiga kelas tersebut memiliki kelas super yang sama yang disebut BentukGeometris. Kelas BentukGeometris memiliki variabel instansi warna, lokasi, dan ukuran. Untuk mengganti warna kita bisa mengganti variabel instansi warna pada kelas ini, kemudian menjalankan metode instansi gambar() untuk menggambar bentuk tersebut dengan warna baru:
class BentukGeometris {
    Color warna;   // Warna suatu bentuk geometri
                   // (Kelas Color diimport dari paket java.awt)
 
    void setWarna(Color warnaBaru) {
        // Metode untuk mengganti warna
        warna = warnaBaru; // ganti nilai variabel instansi
        gambar(); // gambar ulang bentuk geometris ini, dengan warna baru
    }
 
    void gambar() {
        // metode untuk menggambar
        ? ? ?  // perintaha apa yang harus diletakkan di sini?
    }
 
    . . .          // variabel dan metode instansi lain
 
} // akhir kelas BentukGeometris
Sekarang metode gambar() mungkin menjadi serba salah. Masalahnya, setiap bentuk digambar dengan cara berbeda. Metode setWarna() dapat digunakan oleh semua bentuk. Lalu bagaimana komputer tahu bagaimana menggambar bentuk tersebut jika metode gambar() dipanggil? Mudahnya, kita bisa jawab dengan : Komputer akan menjalankan perintah gambar() dengan meminta bentuk tersebut untuk menggambar sendiri. Setiap objek bentuk tahu apa yang harus dilakukan untuk menggambar dirinya.
Dalam prakteknya, ini berarti setiap kelas turunan dari kelas BentukGeometris memiliki metode gambar() sendiri-sendiri, yaitu :
class PersegiPanjang extends BentukGeometris {
    void gambar() {
        . . .  // perintah untuk menggambar persegi panjang
    }
    . . . // metode atau variabel lain
}
 
class Oval extends BentukGeometris {
    void gambar() {
        . . .  // perintah untuk menggambar oval
    }
    . . . // metode atau variabel lain
}
 
class KotakLingkar extends BentukGeometris {
    void gambar() {
        . . .  // perintah untuk menggambar kotak bersudut lingkar
    }
    . . . // metode atau variabel lain
}
Jika gambarku adalah variabel bertipe BentukGeometri, variabel ini bisa merujuk pada objek dengan bertipe PersegiPanjang, Oval, atau KotakLingkar. Ketika program dijalankan, isi variabel gambarku akan berubah-ubah, tergantung pada objek yang dirujuknya. Suatu saat di tengah program, jika perintah gambarku.gambar() dijalankan, maka metode gambar() akan dijalankan tergantung pada isi variabel gambarku saat itu.
Kita tidak akan bisa menebak metode apa yang akan dipanggil pada suatu saat hanya dengan membaca program tersebut, karena kita tidak pernah tahu isi variabel gambarku pada suatu saat tertentu. Misalnya perintah gambar() berada dalam suatu perulangan yang dijalankan berkali-kali. Maka akan sangat mungkin perintah gambarku.gambar() dipanggil berulang-ulang tetapi dengan objek yang berbeda-beda.
Kita sebut metode gambar() bersifat polimorfis. Suatu metode disebut polimorfis jika aksi yang dilakukan oleh suatu metode berbeda-beda tergantung pada objek aktual pada saat metode itu dijalankan. Polimorfisme adalah fitur utama dalam pemrograman berorientasi objek.
Mungkin akan lebih mudah dimengerti jika kita ganti bahasanya : Dalam PBO, memanggil metode sering disebut juga dengan mengirim pesan kepada suatu objek. Objek tersebut merespon pesan tersebut dengan melaksanakan metode yang sesuai. Pernyataan "gambarku.gambar();" adalah pesan yang dikirim ke objek gambarku. Karena objek tersebut tahu jenis objeknya sendiri, dia akan tahu bagaimana merespon pesan tersebut. Dari sudut pandang ini, komputer akan selalu mengeksekusi perintah "gambarku.gambar();" dengan cara yang sama, yaitu dengan mengirim pesan. Pesan tersebut bergantung pada siapa yang menerima pesan tersebut.
Dengan kata lain, objek merupakan sesuatu yang memiliki perilaku aktif, yaitu sesuatu yang bisa mengirim dan menerima pesan. Polimorfisme dianggap sebagai sifat yang natural jika dilihat dari sudut pandang ini. Polimorfisme juga berarti bahwa beberapa objek dapat merespon suatu pesan dengan cara yang berbeda-beda.
Salah satu keindahan dari poliformisme adalah kita bisa membuat kode program tanpa harus mengetahui persis apa yang akan dilakukan program saat kita menulis program tersebut. Jika kita ingin menambah objek lain, misalnya segitiga, maka kita cukup menulis kelas turunan baru dan membuat metode gambar() sendiri. Secara otomatis, program akan tahu jika kita beri perintah "gambarku.gambar()" maka metode gambar() pada kelas segitiga akan dijalankan apabila gambarku menunjuk pada objek yang memiliki kelas segitiga.


Ketika suatu objek, misalnya PersegiPanjang, Oval, atau KotakLingkar, harus menggambar dirinya sendiri, metode gambar() yang sesuai dengan objek yang menerima pesan akan dilaksanakan. Pertanyaannya, apa yang harus kita isi pada metode gambar() di kelas BentukGeometri?
Jawabannya: kosongkan saja. Intinya kelas BentukGeometri adalah kelas abstrak, karena tidak ada cara untuk menggambar BentukGeometri. Apabila kelas tersebut telah direalisasikan dalam suatu bentuk, misalnya PersegiPanjang, barulah objek tersebut bisa menggambar sesuatu.
Lalu kenapa kita harus mendeklarasikan metode gambar() di kelas BentukGeometri? Jawabannya, itu harus ada karena metode ini dibutuhkan untuk memanggil metode setWarna() pada kelas BentukGeometri. Program kita akan menampilkan pesan kesalahan jika kita berikan perintah gambarku.gambar(), karena gambarku bertipe BentukGeometri, apabila di dalam kelas ini tidak ada metode yang bernama gambar().
Kita bisa menyebut kelas BentukGeometri merupakan kelas abstrak. Kelas abstrak adalah kelas yang tidak bisa digunakan untuk membuat suatu objek, dan hanya digunakan untuk membuat kelas turunan. Kelas abstrak hanya ada untuk mengekspresikan sifat umum yang dimiliki oleh kelas-kelas turunannya.
Demikian juga, kita bisa menyebut metode gambar() pada kelas BentukGeometri merupakan metode abstrak, karena metode ini bukan untuk dipanggil. Akan tetapi metode ini ada untuk memberi tahu komputer bahwa semua kelas turunannya mengerti dan bisa menjalankan metode gambar().
BentukGeometri dan metode gambar() secara sematik merupakan kelas dan metode abstrak. Kita juga bisa memberi tahu komputer secara langsung dengan memberi sifat "abstract" pada definisinya. Untuk metode abstrak, blok perintahnya diganti dengan titik koma (;). Metode ini harus diimplementasikan secara detail pada kelas turunannya.
Perhatikan contoh berikut.

abstract class BentukGeometri {
    Color warna;
 
    void setWarna(Color warnaBaru) {
        // metode untuk mengganti warna suatu bentuk
        warna = warnaBaru; // ganti isi variabel instansi warna
        gambar(); // menggambar kembali suatu bentuk dengan warna baru
    }
 
    abstract void gambar();
        // metode abstrak yang harus diimplementasikan
        // pada kelas turunannya
 
        . . .          // variabel dan metode instansi lainnya
 
} // akhir kelas BentukGeometri
Setelah kita buat seperti ini, kita tidak bisa lagi membuat objek langsung dari kelas BentukGeometri.

Dalam Java, setiap kelas yang kita buat akan memiliki kelas super, atau dengan kata lain setiap kelas merupakan turunan dari kelas lain. Jika kita tidak memberi kelas supernya (melalui operator extends), maka kelas tersebut otomatis memiliki kelas super Object, yaitu kelas bawaan yang sudah didefinisikan dalam paket java.lang. Kelas Object adalah satu-satunya kelas yang tidak memiliki kelas super.

Jadi dengan demikian, perintah,
class Kelasku { ... }
sama artinya dengan
class Kelasku extends Object { . . . }
Semua kelas akan merupakan turunan langsung atau tidak langsung dari kelas Object. Artinya suatu obek yang merupakan kelas apapun dapat direferensikan oleh variabel bertipe Object. Kelas Objek memiliki sifat-sifat umum yang dapat digunakan oleh semua objek. Kelas Object adalah kelas yang paling abstrak dari kelas-kelas lainnya.
Kelas Object digunakan dalam beberapa kasus di mana kumpulan objek yang sangat umum ingin diolah. Misalnya, Java memiliki kelas standar java.util.ArrayList yang merupakan kumpulan Objects. ArrayList akan dibahas kemudian dalam topik tentang struktur data dan algoritma. Kelas ini digunakan untuk menampung kumpulan objek, tak ditentukan jumlahnya, dan bisa diperbanyak ketika objek baru ditambahkan. Objek yang dapat ditampung pada dasarnya adalah semua objek dari beragam kelas.
Kita dapat juga membuat program untuk menampung semua BentukGeometri yang telah digambar di layar dalam kontainer ArrayList. Milsanya ArrayList kita bernama kumpulanGambar. Suatu objek dengan tipe BentukGeometri misalnya gambarku dapat ditambahkan ke dalam kumpulan ini dengan menggunakan perintah "kumpulanGambar.add(gambarku);". Gambar tersebut dapat dibuang dari dalam kumpulan dengan perintah "kumpulanGambar.remove(gambarku);". Jumlah obejk dalam kumpulanGambar dapat diubah dengan perintah "kumpulanGambar.size()". Juga kita bisa mengambil gambar ke-n dari dalam kumpulanGambar dengan perintah "kumpulanGambar.get(n);". Perlu diingat bahwa metode tersebut akan mengembalikan objek bertipe Object bukan BentukGeometri, dan sebetulnya kontainer ini bisa menampung objek apa saja, bukan hanya BentukGeometri, sehingga untuk mengambil objek ke-n yang kemudian kita letakkan dalam variabel bertipe BentukGeometri, kita bisa gunakan perintah.
gambarku = (BentukGeometri)kumpulanGambar.get(n);
Katakan misalnya kita ingin menggambar semua objek dengan berbagai tipe di dalam kumpulan tersebut, kita bisa gunakan perulangan for sederhana (sekaligus memberi contoh betapa indagnya PBO dan polimorfisme), yaitu dengan :
for (int n = 0; n < kumpulanGambar.size(); n++) {
    BentukGeometri bg = (BentukGeometri)kumpulanGambar.get(n);
    bg.gambar();
}

Tambahan
Dalam pemrograman sehari-hari, terutama bagi programmer yang baru belajar dan bekerja dengan objek, penurunan kelas akan sering digunakan. Salah satunya adalah untuk memperluas kegunaan suatu kelas, yang disesuaikan dengan situasi dan kondisi permasalahan yang kita hadapi. Kita bisa membuat kelas baru yang merupakan turunan kelas yang sudah ada, menambah beberapa variabel dan metode instansi baru, yaitu dengan operator extends seperti dijelaskan sebelumnya pada bagian ini.
Secara umum, sintaksnya adalah dalam bentuk
class kelas_turunan extends kelas_yang_sudah_ada {
   ... // tambahan atau perubahan variabel dan metode instansi
}
Kita akan lihat nanti bahwa banyak kelas-kelas standar pada Java yang digunakan hanya sebagai kelas dasar yang untuk dikembangkan lebih jauh oleh kita sebagai programmer.

Tuesday

Pemrograman Berorientasi Objek

Class adalah struktur dasar dari pemrograman berorientasi objek yang mendefinisikan variable dan method-method pada seluruh objek tertentu. Class juga mendefinisikan tipe data baru untuk menciptakan model dari objek yang dibuat sesuai dengan tipe data baru tersebut. Dengan kata lain class menciptakan instant dari objek. class juga merupakan grup suatu object dengan kemiripan attributes/properties, behaviour dan relasi ke object lain.

Objek adalah instance dari class. Objek merupakan perangkat lunak yang berisi sekumpulan variable dan method-method terkait. Objek merupakan entitas yang memiliki keadaan, behaviour dan identitas yang tugasnya dirumuskan dalam suatu lingkup masalah dengan baik.

Instantiate adalah proses pembentukkan objek dari suatu class.

Instance Variable adalah variable yang ada di dalam class tetapi berada di luar method. Instance variable ini merupakan attribute dari suatu class dan mempunyai default value yang tidak perlu diinisialisasi.

Instance Method merupakan method yang hanya tersedia apabila instance dari suatu class dibuat.

Class Variable (Static Member Variables) adalah variable yang dimiliki oleh class yang dapat memiliki nilai yang sama untuk semua objek pada class yang sama dan dapat diakses oleh semua instance dari class.

Konstruktor adalah sebuah tipe khusus dari method yang digunakan untuk membuat dan menginisialisasi sebuah object baru. Konstruktor merupakan suatu method yang memiliki nama yang sama dengan nama classnya.

Mari kita bahas satu-persatu,
Objek, Metode Instansi dan Variable Instansi
Konstruktor dan Inisialisasi Objek
Pewarisan, Polimorfisme, dan Kelas Abstrak 
Variabel this dan super 
Interface, Class Bertingkat, dan Detail Lain

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.
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:
  1. Pertama, komputer memberi daerah pada memori yang tidak digunakan, cukup untuk dipakai oleh objek yang akan dibuat
  2. 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.
  3. Parameter aktual pada konstruktor (jika ada) akan dievaluasi dan nilainya diberikan kepada parameter formal konstruktor tersebut.
  4. Perintah pada konstruktor (jika ada) akan dilaksanakan.
  5. 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.

Objek, Metode Instansi dan Variable Instansi

Pemrograman berorientasi objek bermaksud untuk memecahkan masalah programming mirip dengan cara berfikir manusia dan bagaimana manusia berinteraksi dengan dunia. Kita telah melihat bagaimana masalah programming dipecahkan dengan membaginya menjadi instruksi-instruksi kecil yang dirangkai menjadi suatu kesatuan tugas. Cara ini disebut juga dengan pemrograman berdasarkan prosedur.

Pada pemrograman berorientasi objek, kita membagi masalah pemrograman berdasarkan objek atau "sesuatu" benda. Objek ini diibaratkan seperti makhluk hidup, yaitu memiliki ciri-ciri fisik dan juga perilaku. Dalam pemrograman berorientasi objek, ciri-ciri fisik ini disebut juga sebagai atribut, pada dasarnya berisi informasi tentang objek tersebut. Sedangkan perilaku disebut sebagai metode, yaitu bagaimana suatu objek bertindak atau melakukan sesuatu.

Dengan cara ini diharapkan pemrograman berorientasi objek merupakan pemrograman yang lebih alami dibandingkan dengan pemrograman berorientasi prosedur, karena cara fikir kita sudah terbiasa dengan bagaimana kita berinteraksi dengan dunia.

Sampai tingkat tertentu, PBO hanya merubah cara pandang programmer. Objek dalam kaitannya dengan dasar pemrograman adalah gabungan dari variabel (dalam hal ini atribut) dan subrutin (yaitu metode) yang berinteraksi dengan variabel pada objek.

Banyak bahasa pemrograman lain yang juga mendukung konsep PBO, akan tetapi Java merupakan bahasa yang mendukung penuh PBO, di antaranya karena Java memiliki beberapa fitur penting yang berbeda dari bahasa standar. Untuk menggunakan fitur ini, kita harus mengubah cara pandang kita terlebih dahulu.

Objek terkait erat dengan kelas. Kita telah bahas dan mencoba beberapa contoh kelas pada bab-bab sebelumnya. Seperti kita lihat pula bahwa kelas memiliki variabel dan subrutin.

Jika objek juga memiliki variabel dan subrutin, lalu apa bedanya dengan kelas? Lalu mengapa kita harus memiliki cara pandang berbeda dengan cara kita melihat kelas? Sepertinya apabila kita lihat contoh-contohnya sebelumnya, perbedaannya hanya menghilangkan kata "static" dari deklarasi variabel dan subrutinnya, khan?

Seperti disebutkan sebelumnya bahwa kelas mendeskripsikan suatu objek, atau lebih tepatnya, bagian non "static" mendeskripsikan suatu objek. Mungkin bahasa biologi, kelas adalah species, sedangkan objek merupakan individu. Human sapiens (nama biologi manusia) adalah kelas, sedangkan Anda, saya, ibu, bapak, pak hansip adalah objek. Masing-masing dari kita memiliki "blueprint" atau cetak biru yang sama, tetapi kita memiliki ciri-ciri yang berbeda, rambut, mata, telinga, tinggi badan, berat badan, dan juga perilaku kita saat makan, minum, belajar, dan lain-lain.

Dalam sudut pandang pemrograman, kelas digunakan untuk menciptakan suatu objek. Atau dengan kata lain, kelas adalah pabrik pembuat objek. Bagian non-statik dari suatu kelas adalah bagian yang memuat detail suatu objek, yaitu apa isi variabel dan metodenya. Perbedaan kelas dan objek adalah : Objek diciptakan dan dihancurkan ketika program berjalan, sehingga kita bisa memiliki beberapa objek sekaligus.

Kita lihat contoh sederhana, dimana kelas sederhana digunakan untuk menggabungkan beberapa variabel statik. Misalnya
class DataPenduduk {
    static String nama;
    static int umur;
}
Dalam hal ini tidak ada lagi yang variabel DataPenduduk.nama dan DataPenduduk.umur, karena nama dan umur bukan anggota statik kelas DataPenduduk. Jadi, tidak ada yang bisa kita lakukan dengan kelas ini sama sekali, kecuali membuat objek dari kelas ini.

Setiap objek akan memiliki variable sendiri yang dinamakan "nama" dan "umur". Kita bisa membuat banyak "penduduk" karena kita bisa membuat objek untuk setiap penduduk. Misalnya setiap kali seseorang dilahirkan, kita bisa membuat objek penduduk baru. Atau jika seseorang meninggal dunia, kita bisa hapus objek tersebut.

Suatu sistem yang terdiri dari kumpulan objek digunakan untuk memodelkan apa yang terjadi di alam nyata. Kita tidak bisa membuat beberapa objek dengan menggunakan variabel statik.

Contoh lainnya adalah pada GUI. Bayangkan kita memiliki beberapa tombol, misalnya tombol OK, Cancel dan Apply. Masing-masing tombol ini memiliki kelas yang sama akan tetapi apa yang dilakukan tombol ini berbeda-beda. Teks yang ditampilkan (OK, Cancel atau Apply) merupakan variabel masing-masing objek.

Suatu objek yang diciptakan dari suatu kelas disebut instansi dari kelas tersebut. Variabel yang dimiliki oleh objek disebut variabel instansi. Sedangkan subrutinnya disebut <="" strong="">. (Dalam PBO subrutin disebut metode)

Misalnya dalam kelas DataPenduduk di atas, kemudian kita buat suatu objek dari kelas ini, maka objek yang diciptakan disebut instansi dari kelas DataPenduduk, "nama" dan "umur" adalah variabel instansi di dalam objek tersebut.

Penting untuk diingat bahwa kelas suatu objek menentukan tipe data dari variabel instansi, akan tetapi isi datanya sendiri tidak disimpan di dalam kelas, akan tetapi di dalam objek yang diciptakan, sehingga setiap objek akan memiliki data masing-masing.

Begitu juga dengan metode instansi, misalnya pada kelas tombol, kita memiliki metode yang dinamakan klik(). Masing-masing tombol akan melakukan tugas berbeda-beda tergantung dari objeknya.

Seperti kita lihat di sini bahwa bagian statik dan non-statik dari suatu kelas merupakan hal yang sama sekali berbeda. Banyak kelas yang hanya memiliki anggota statik, atau hanya memiliki anggota non-statik. Akan tetapi kita juga bisa mencampur keduanya dalam suatu kelas. Variabel anggota statik suatu kelas juga bisa disebut variabel kelas dan metode anggota statik suatu kelas juga bisa disebut metode kelas, karena mereka adalah milik kelas dan bukan milik objek yang diciptakan dari suatu kelas.

Sekarang kita gunakan contoh yang lebih real. Kita akan buat versi sederhana dari kelas Murid, dimana kita akan menyimpan informasi tentang murid yang terdaftar pada suatu sekolah.
class Murid {
    String nama ;    // nama murid
    double nilai1, nilai2, nilai3;    // nilai ulangan murid tersebut
    double hitungRataRata() {    // hitung rata-rata nilai ulangan
        return (nilai1 + nilai2 + nilai3) / 3;
    }
}
Kita lihat bahwa semua anggota kelas tersebut bukan anggota statik, artinya kelas ini hanya bisa digunakan untuk membuat objek. Definisi kelas ini artinya bahwa di dalam objek yang akan diciptakan, akan ada variabel instansi yang bernama nama, nilai1, nilai2, dan nilai3, dan juga metode instansi yang bernama hitungRataRata(). Setiap murid memiliki nilai rata-rata yang berbeda-beda. (Makanya ini disebut perilaku suatu objek berbeda-beda).

Dalam Java, kelas merupakan tipe data, yaitu mirip dengan tipe data bawaan seperti int atau boolean. Jadi nama kelas bisa digunakan untuk menentukan tipe suatu variabel dalam deklarasi pernyataan, dalam parameter formal dan juga dalam tipe keluaran suatu fungsi. Misalnya, program mendefinisikan seorang murid dengan pernyataan seperti :
Murid amir;
Akan tetapi membuat variabel seperti di atas TIDAK menciptakan objek. Initinya, ini adalah hal Yang Sangat Amat Penting :
Dalam Java, tidak ada variabel yang bisa menyimpan objek. Variabel hanya bisa menyimpan referensi (alamat di memori) suatu objek. Komputer akan menggunakan referensi ini untuk mencari objek di dalam memori.
Objek diciptakan dengan pernyataan new, yang bertugas menciptakan objek kemudian mengembalikan referensi ke objek yang sudah diciptakan. Misalnya amir adalah variabel dengan tipe Murid seperti dideklarasikan di atas, maka pernyataan berikut :
amir = new Murid();
akan membuat objek yang merupakan instansi dari kelas Murid. Variabel amir akan menyimpan referensi ke objek yang baru saja diciptakan.
Sekarang anggap variabel amir merujuk pada objek yang diciptakan dari kelas Murid. Dalam objek tersebut terdapat variabel nama, nilai1, nilai2, dan nilai3. Variabel instansi ini bisa dipanggil dengan amir.nama, amir.nilai1, amir.nilai2, dan amir.nilai3. (Ingat aturan penulisan nama lengkap, akan tetapi karena kelas ini tidak memiliki anggota statik, dan hanya objek yang diciptakan dari kelas ini memiliki variabel atau metode ini, maka nama lengkapnya diturunkan dari nama objek yang memilikinya).
Misalnya, program berikut :
System.out.println("Hai, " + amir.nama + " . Nilai Anda adalah : ");
System.out.println(amir.nilai1);
System.out.println(amir.nilai2);
System.out.println(amir.nilai3);
Program di atas akan mencetak nama dan nilai-nilai yang disimpan oleh objek amir. Begitu juga kita bisa menghitung rata-rata pada suatu objek dengan menggunakan amir.hitungRataRata(). Sehingga untuk menghitung rata-rata murid tersebut, bisa kita perintahkan dengan:
System.out.println("Nilai rata-rata Anda adalah : " + amir.hitungRataRata());
Lebih umum lagi, kita bisa menggunakan amir.nama seperti layaknya variabel bertipe String, artinya kita bisa menghitung jumlah karakter dengan menggunakan amir.nama.length().
Kita juga bisa membuat variabel seperti amir untuk tidak menunjuk atau memiliki referensi ke obek mana pun. Dalam hal ini kita sebut bahwa objek amir berisi referensi kosong (null reference). Referensi kosong ini ditulis dalam Java dengan ekspresi "null". Dan kita bisa menyimpan nilai "null" pada variabel amir dengan perintah :
amir = null;
Dan kita juga bisa uji apakah amir berisi referensi kosong dengan perintah
if (amir == null) . . .
Jika suatu variabel berisi referensi kosong, maka tentu saja, kita tidak bisa mengambil variabel instansi dan menjalankan metode instansi, karena tidak ada objek yang dirujuk pada variabel tersebut. Misalnya jika variabel amir berisi null, maka kita tidak bisa mengambil variabel amir.nilai1.
Jika program kita mencoba mengakses referensi kosong secara ilegal, maka di tengah-tengah jalannya program, program akan menampilkan pesan kesalahan "null pointer exception".
Mari kita lihat beberapa pernyataan yang bisa digunakan dengan objek :
Murid mrd1, mrd2, mrd3, mrd4;    // mendeklarasikan 4 variabel yang bertipe Murid
mrd1 = new Murid();              // membuat objek baru dari kelas Murid, kemudian menyimpan referensinya pada variabel mrd1
mrd2 = new Murid();              // membuat objek baru dari kelas Murid, kemudian menyimpan referensinya pada variabel mrd2
mrd3 = mrd1;                     // menkopi „referensi" yang disimpan pada mrd1 ke mrd3
mrd4 = null;                     // menyimpan referensi kosong ke mrd4
 
mrd1.nama = "Ahmad Surahmat";    // mengisi nilai variabel instansi
mrd2.nama = "Hamid Samsudin";
Setelah komputer menjalankan program tersebut, maka kira-kira memori komputer akan tampak seperti gambar berikut :

Gambar tersebut menunjukkan variabel dalam kotak-kotak kecil dengan nama variabelnya. Objek ditunjukkan dalam kotak dengan pojok bulat. Ketika suatu variabel berisi referensi ke suatu objek, maka nilainya adalah seperti panah yang menunjuk pada objek tersebut.
Variabel mrd4 bernilai null, sehingga tidak menunjuk ke mana-mana. Panah dari mrd1 dan mrd3 menjunjuk pada objek ang sama. Ini merupakan Hal Yang Sangat Penting :
Jika isi variabel suatu objek diberikan kepada variabel yang lain, maka yang dikopi hanya referensinya saja. Isi objek tidak pernah dikopi.
Ketika pernyataan "mrd3 = mrd1;" dieksekusi, tidak ada objek baru yang dibuat. Akan tetapi mrd3 akan merujuk pada alamat yang sama seperti mrd1. Konsekuensinya mungkin sedikit mengejutkan. Misalnya variabel mrd1.nama dan mrd3.nama menunjuk pada variabel yang persis sama, maka apabila mrd1.nama disi dengan "Juju Juminten", maka mrd3.nama juga berisi "Juju Juminten".
Sekali lagi, variabel tidak berisi objek, akan tetapi berisi referensi ke suatu objek.
Kita bisa menguji beberapa objek dengan operator == dan != untuk menguji kesamaan dan ketidaksamaan. Akan tetapi yang dicek lagi-lagi bukan isi objek, melainkan alamat memori dimana objek tersebut dijadikan referensi. Jika alamat referensi di memori sama, artinya kedua objek tersebut merujuk pada alamat memori yang sama. Ini berarti perubahan yang dilakukan pada variabel yang satu akan ikut mempengaruhi variabel yang lain.
Untuk menguji isinya, maka isinya harus dibandingkan satu per satu, yaitu misalnya dengan "mrd3.nilai1 == mrd1.nilai1 && mrd3.nilai2 == mrd1.nilai2 && mrd3.nilai3 == mrd1.nilai3 && mrd3.nama.equals(mrd1.nama)"
Seperti telah disebutkan sebelumnya bahwa String juga merupakan objek. Sehingga membandingkan String yang satu dengan String yang lain dengan menggunakan tanda == adalah membandingkan apakah alamat memori yang ditunjuk oleh String yang satu sama dengan alamat memori yang ditunjuk oleh String yang lain. Ingat == pada objek bukan membandingkan isi objek, tetapi membandingkan alamat memori yang ditunjuk oleh variabel tersebut. Untuk membandingkan isi String, kita dapat menggunakan String.equals() di mana parameternya adalah objek String yang akan dibandingkan. Metode ini akan membandingkan karakter per karakter dari kedua String.
Misalnya, variabel salam berisi String "Selamat". Untuk menguji apakah variabel salam berisi "Selamat", bisa kita gunakan perintah,
salam.equals("Selamat")
Konsekuensi lainnya adalah apabila suatu variabel merujuk pada objek yang dideklarasikan sebagai final. Ini berarti nilai variabel itu tidak bisa berubah setelah diinisialisasi, sedangkan isi variabel itu adalah rujukan ke alamat memori tempat objek berada. Dengan demikian variabel tersebut akan selalu menunjuk pada alamat memori yang sama. Akan tetapi hal ini tidak berlaku untuk objek itu sendiri. Apabila ada variabel lain yang tidak "final" tetapi menunjuk pada alamat memori yang sama, kemudian variabel ini mengubah isi objek tersebut, maka isi objek tersebut bisa berubah.
Kita boleh saja untuk menulis perintah sebagai berikut.
final Murid mrd = new Murid();
murid.nama = "Ahmad Basir";
Perhatikan pada kode di atas bahwa isi objek bisa diubah. Akan tetapi jika kita mencoba menulis seperti ini
Murid mrd99 = new Murid();
mrd = mrd99; // ILEGAL, karena mrd adalah variabel final