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

Thursday

Variabel this dan super

Variabel spesial this dan super
Anggota statik suatu kelas bisa digunakan langsung di dalam kelas tersebut. Untuk digunakan di kelas lain, maka ia harus dipanggil dengan nama lengkapnya dalam bentuk "namaKelas.namaAnggota", misalnya "System.out" adalah variabel anggota statik dengan nama "out" di dalam kelas "System". Kita bisa menggunakan nama lengkap kelas tersebut di manapun, bahkan dari dalam kelas yang sama, misalnya karena nama anggota tersebut disembunyikan oleh variabel lokal yang namanya sama.
Variabel dan metode instansi juga bisa digunakan langsung di dalam kelas tersebut, misalnya suatu variabel instansi bisa digunakan langsung oleh metode instansi di kelas yang sama. Anggota instansi juga memiliki nama lengkap akan tetapi ingat bahwa anggota instansi dimiliki oleh objek, bukan kelas. Sehingga untuk memanggil suatu anggota instansi, kita harus menggunakan nama objek yang diciptakan dari kelas tersebut, dalam bentuk namaObjek.namaAnggota.
Akan tetapi, misalnya kita sedang menulis metode instansi di suatu kelas. Bagaimana caranya kita memanggil anggota instansi kelas yang sama jika kita belum tahu nama objek apa yang diciptakan dari kelas ini?
Java memiliki variabel spesial yang dinamakan "this" yang bisa digunakan untuk kasus di atas. Variabel ini digunakan pada suatu objek untuk memanggil metode atau variabel instansi pada objek yang sama. Maksudnya, this, merujuk pada "objek ini" yaitu objek di mana metode sedang dijalankan. Jika x adalah variabel instansi dalam suatu objek, maka this.x adalah nama lengkap variabel tersebut jika dipanggil dari dalam objek yang sama. Jika metode suatuMetode() adalah metode instansi pada suatu objek, maka this.suatuMetode() bisa digunakan untuk memanggil metode tersebut dari objek yang sama. Ketika komputer menjalankan perintah tersebut, komputer akan mengganti variabel this dengan objek yang berjalan pada saat itu.
Salah satu kegunaaan this adalah pada konstruktor, misalnya :
public class Murid {
    private String nama;  // Nama murid
 
    public Murid(String nama) {
        // Konstruktor, membuat murid dengan nama yang diberikan
        this.nama = nama;
    }
    .
    .   // Variabel dan metode lain.
    .
}
Dalam konstruktor di atas, variabel instansi nama disembunyikan oleh parameter formal yang bernama sama. Akan tetapi, variabel instansi masih tetap bisa dipanggil dengan nama lengkapnya, this.nama. Cara ini merupakan cara yang lazim, artinya kita tidak perlu mengganti nama parameter formal dengan nama lain agar namanya tidak bentrok dengan nama salah satu variabel instansinya. Kita bisa menggunakan nama parameter formal yang sama persis dengan variabel instansinya.
Ada lagi kegunaan lain dari this. Ketika kita sedang menulis metode instansi, kita ingin memberikan objek sebagai parameter aktual. Dalam hal ini, kita bisa menggunakan this sebagai parameter aktualnya. Misalnya, kita ingin mencetak suatu objek sebagai string, kita bisa menggunakan perintah "System.out.println(this);". Atau kita ingin mengisi nilai this ke dalam variabel lain. Pokoknya, kita bisa melakukan segala hal seperti layaknya variabel kecuali mengganti isinya.


Java juga memiliki variabel spesial yang dinamakan "super" untuk digunakan dalam metode instansi. Variabel super digunakan dalam kelas turunan. super mengacu pada objek di mana metode tersebut berada, akan tetapi ia merupakan bagian dari kelas super dari objek tersebut.
Suatu kelas bisa ditambah atau dimodifikasi dari kelas turunannya. Variabel super hanya mengacu pada bagian objek sebelum ia ditambah atau dimodifikasi, atau dengan kata lain bentuk aslinya sebelum dia diturunkan, yang dalam hal ini sama dengan kelas supernya.
Misalnya kita akan menulis suatu kelas, dan kelas tersebut memiliki metode instansi bernama suatuMetode(). Pernyataan super.suatuMetode() berarti menjalankan suatuMetode() pada kelas supernya. Jika tidak ada metode sutuMetode() pada kelas supernya, Java akan menampilkan pesan kesalahan sintaks.
Alasan mengapa Java memiliki variabel super adalah karena banyak hal yang mungkin tersembunyi pada kelas turunan. Misalnya karena kita mengimplementasikan fungsi lain pada kelas turunan dengan nama yang sama (dalam kaitannya dengan polimorfisme, misalkan).
Ketika kita membuat metode baru pada kelas turunan yang memiliki nama dan jenis parameter yang sama dengan metode pada kelas supernya, metode dari kelas super akan disembunyukan. Dalam bahasa pemrograman, metode ini menimpa (override) metode dari kelas supernya. Variabel super bisa digunakan untuk mengakses metode aslinya yang didefinisikan di kelas supernya.
Kegunaan utama dari super biasanya untuk memperluas kegunaan metode yang sudah ada, bukan menggantinya secara keseluuruhan. Metode baru bisa menggunakan super untuk menjalankan instruksi pada kelas supernya, kemudian menambahkan instruksi lain pada kelas turunannya.
Misalnya, kita memiliki kelas PasanganDadu yang memiliki metode kocok. Kemudian kita akan membuat kelas turunan yaitu DaduGrafis yang berfungsi untuk menggambar dadu pada layar. Metode kocok() dalam DaduGrafis harus melakukan apa yang dilakukan oleh PasanganDadu, dengan tambahan perintah untuk menggambar dadu tersebut di layar. Kita bisa tulis definisi kelas DaduGrafis dalam bentuk :
public class DaduGrafis extends PasanganDadu {
    public void kocok() {
        // Mengocok dadu, kemudian menggambarnya di layar
        super.kocok();  // Panggil metode kocok() di kelas PasanganDadu
        gambar();      // Gambar ulang dadu
    }
    .
    .  // Metode dan variabel lain, termasuk metode gambar()
    .
}
Dengan cara ini kita bisa memperluas apa yang dilakukan oleh metode kocok() pada kelas supernya tanpa mengetahui dengan detail apa yang dilakukan langkah per langkah di kelas supernya.

Konstuktor pada Kelas Turunan
Konstruktor tidak bisa diturunkan, artinya jika kita membuat kelas turunan dari suatu kelas, konstruktor pada kelas supernya tidak termasuk bagian yang diturunkan. Jika kita ingin konstruktor tersebut pada kelas turunannya, maka kita harus membuat kembali konstruktor tersebut di kelas yang baru. Jika tidak, maka Java akan membuat konstruktor standar tanpa parameter apa-apa.
Hal ini mungkin menjadi masalah jika konstruktor pada kelas supernya melakukan banyak tugas. Artinya kita harus mengulang kembali menuliskan semua instruksi pada kelas supernya di kelas turunan yang baru. Masalahnya akan lebih rumit jika kita tidak mengetahui sama sekali apa yang dilakukan kelas supernya, misalnya apabila tidak ada kode sumbernya.
Cara yang paling mudah adalah menggunakan super. Di baris pertama konstruktor baru kita di kelas turunannya, kita bisa menggunakan super untuk memanggil konstruktor kelas supernya. Sintaksnya sedikit aneh dan membingungkan, dan hanya bisa digunakan untuk satu situasi saja : Sintaksnya mirip seperti memanggil subrutin super (meskipun sebenarnya super bukan subrutin dan kita tidak bisa memanggil konstruktor seperti kita memanggil subrutin biasa).
Misalnya kelas PasanganDadu memiliki konstruktor yang memiliki dua parameter bertipe int. Maka kita bisa membuat konstruktor pada kelas DaduGrafis seperti :
public class DaduGrafis extends PasanganDadu {
 
    public DaduGrafis() {  // Konstruktor kelas ini
        super(3,4);  // Panggil konstruktor dari kelas PasanganDadu
                     // dengan parameter 3 dan 4
        inisialisasiGrafis();  // Lakukan inisialisasi grafis
                               // untuk digunakan pada kelas DaduGrafis
    }
    .
    .  // Konstruktor, variabel dan metode instansi lain
    .
}

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.