Java dan OOP - Bagian 2
OOP didasarkan pada pendefinisian kelas untuk merepresentasikan objek-objek dengan karakteristik dan fungsionalitas yang terdefinisi dengan baik. Untuk program-program yang sederhana kita cukup menggunakan pustaka (class library) yang sudah disediakan oleh Java. Sedangkan untuk aplikasi yang lebih kompleks, biasanya kita perlu menulis dan menyusun kelas-kelas sendiri, disesuaikan dengan fungsi aplikasi yang akan dibuat. Bagian-bagian pemecahan masalah dapat didistribusikan dalam kelas-kelas yang masing-masing melakukan tugas tertentu. Dalam bagian ini kita akan membahas beberapa topik OOP dalam bahasa Java.
Membentuk Objek
Sebuah variabel dapat menyimpan nilai dari tipe data primitif atau berupa referensi ke sebuah objek. Yang pertama disebut variabel primitif dan yang kedua variabel objek atau variabel referensi. Sebuah variabel primitif langsung memuat nilai data tersebut, sedangkan variabel objek berisi alamat (address) dari objek terkait. Referensi ini bisa dipandang sebagai pointer ke lokasi objek yang sesungguhnya, sebagaimana kita kenal dalam bahasa pemrograman seperti C/C++. Ilustrasi ke dua jenis variabel ini diberikan dalam Gambar 1.10. Gambar 1.10. Contoh visualisasi variabel primitif dan variabel objek
Sebagaimana variabel primitif, variabel objek juga perlu dideklarasikan. Untuk deklarasi variabel jenis ini digunakan nama kelas dari objek yang diinginkan:
String judul;
Deklarasi ini tidak secara otomatis membentuk objek. Objek dibentuk menggunakan operator new
, misalnya:
judul = new String("Java is fun!");
Bagian String("Java is fun!"
) disebut konstruktor (constructor), dalam hal ini konstruktor kelas String. Konstruktor merupakan metode khusus yang digunakan untuk “menciptakan” objek. Proses pembentukan objek biasanya disebut sebagai instantiation dan sebuah objek disebut instansi (instance) dari kelasnya.
Setelah objek terbentuk, kita dapat menggunakan operator titik (dot) untuk memanggil sebuah metode, misalnya :
jumlah = judul.length();
Sebuah metode bisa memberikan nilai balik (returned value) yang bisa digunakan dalam ekspresi atau penugasan. Dalam contoh diatas, nilai balik dari metode length()
digunakan dalam proses penugasan pada variabel jumlah. Dalam konteks OOP, pemanggilan metode dapat dianggap sebagai “meminta sebuah objek untuk melakukan servis tertentu”.
Untuk variabel primitif proses penugasan (assignment) merupakan proses menyalin nilai untuk disimpan dalam variabel. Secara visual dapat digambarkan sebagai berikut: Gambar 1.11. Ilustrasi proses assignment untuk variabel primitif
Sedangkan untuk variabel objek, proses assignment merupakan proses menyalin alamat dari objek yang ditunjuk oleh sebuah variabel, ke variabel yang lain. Ilustrasinya sebagai berikut. Gambar 1.12. Ilustrasi proses assignment untuk variabel objek
Dua atau lebih referensi yang menunjuk pada objek yang sama disebut sebagai alias. Hal ini membuat sebuah konsekuensi: sebuah objek bisa diakses menggunakan lebih dari satu variabel referensi.
Alias dapat digunakan untuk berbagai keperluan manipulasi objek. Walaupun berguna, alias harus digunakan secara hati-hati. Mengubah objek melalui sebuah alias, berarti mengubah objek tersebut bagi semua alias yang lain, karena pada kenyataannya hanya ada sebuah objek.
Kalau sebuah objek tidak lagi mempunyai satupun referensi yang valid, objek tersebut tidak bisa lagi diakses oleh program. Dengan kata lain, objek ybs tidak lagi berguna, sehingga disebut garbage (sampah). Java melakukan proses garbage collection secara otomatis dan periodik, untuk membebaskan dan mengembalikan memori kepada sistem supaya dapat digunakan untuk keperluan lain. Dalam bahasa pemrograman lain, biasanya programmer yang harus melakukan dan bertanggung jawab terhadap pengelolaan garbage ini.
Enkapsulasi
Sebuah objek (misalnya objek A) bisa menggunakan objek lain (objek B) untuk melakukan fungsinya. Dalam hal ini objek A adalah klien (client) dari objek B. Klien dari sebuah objek bisa dan diperbolehkan untuk meminta “servis” dengan memanggil metode dari objek yang bersangkutan. Dalam konsep OOP, klien tidak perlu aware tentang bagaimana servis tersebut dilaksanakan. Hal ini, karena sebuah objek harus mandiri (self governing) dan setiap perubahan pada state (yang tidak lain berupa variabel) harus dilakukan oleh/melalui metode dari objek tersebut.
Objek bisa dipandang dari dua perspektif yang berbeda:
- Internal : merupakan detil variabel dan metode dari kelas yang mendefinisikannya.
- Eksternal : merupakan entitas penyedia servis yang bisa berinteraksi dengan sistem dan objek-objek lain.
Jadi, dari sudut pandang eksternal, sebuah objek adalah entitas ter-enkapsulasi (tertutup) yang menyediakan servis tertentu. Servis ini mendefinisikan antarmuka (interface) dari dan ke sebuah objek. Dengan kata lain, objek bisa dianggap sebagai kotak hitam yang cara kerja-nya tersembunyi dari dunia luar. Klien hanya bisa memangil metode-metode yang menjadi antarmuka objek. Metode-metode ini lah yang berperan dan bertanggung-jawab dalam mengatur state/data di dalam objek (lihat Gambar 1.13).
Dalam Java, enkapsulasi dilakukan melalui pemakaian visibility modifier yang sesuai. Sebuah modifier adalah bagian dari pengenal khusus (reserved words) yang memberikan sifat spesifik bagi metode dan data. Istilah final
yang telah kita gunakan di atas dalam pembahasan konstanta merupakan sebuah modifier.
Gambar 1.13. Enkapsulasi objek
Java mempunyai tiga visibility modifier, yaitu: public
, protected
dan private
.
Variabel dengan tipe public tidak dipakai untuk enkapsulasi, karena klien dapat mengakses “ke dalam” dan mengubah nilai variabel secara langsung. Sedangkan konstanta dengan tipe public masih dapat diterima, karena walaupun klien dapat mengaksesnya, nilai konstanta tidak bisa diubah. Konstanta public juga memungkinkan penggunaan di luar kelas dimana ia didefinisikan.
Metode dan data yang dideklarasikan dengan tipe public dapat dipanggil dimana saja. Sedangkan metode dan data yang mempunyai tipe private hanya dapat dipanggil di dalam kelas yang bersangkutan. Bila dalam deklarasi tidak digunakan visibility modifier, Java mengasosiasikannya sebagai tipe default visibility dan bisa dipanggil oleh setiap kelas dalam paket yang sama.
Metode-metode yang menjadi antarmuka dengan “dunia luar” harus dideklarasikan dengan tipe public. Metode-metode ini disebut sebagai metode servis (service methods). Sedangkan metode pembantu yang digunakan dalam menyediakan servis, disebut support methods. Karena tidak dimaksudkan untuk dipanggil langsung oleh klien, metode pembantu sebaiknya tidak didefinisikan dengan tipe public.
Karena data harus bertipe private, sebuah kelas biasanya menyediakan servis untuk mengakses dan memodifikasi nilai data. Metode pengakses (accessor) adalah metode sederhana untuk mengakses data dengan memberikan nilai balik dari sebuah variabel. Sedangkan metode mutator digunakan untuk mengubah nilai sebuah variabel. Konvensi penulisan yang lazim bagi kedua metode ini adalah setX
untuk mutator dan getX
untuk pengakses, dimana X adalah nama variabel yang dimaksud. Sehingga, seringkali metode mutator disebut sebagai “setter” dan metode pengakses disebut sebagai “getter”.
Inheritansi
Inheritansi (inheritance) merupakan konsep mendasar dalam OOP, yang bertujuan untuk membuat skema dan mekanisme reusable code. Pada prinsipnya, inheritansi adalah pembuatan sebuah kelas baru dari sebuah kelas yang sudah ada. Kelas yang baru ini disebut sebagai kelas turunan atau subkelas atau child class. Sedangkan kelas yang menurunkan, disebut sebagai kelas induk atau kelas basis atau super/parent class. Gambar 1.14. Hubungan inheritansi secara visual
Kelas turunan “mewarisi” karakteristik kelas induknya. Karakteristik yang dimaksud tentu saja adalah metode dan data yang didefinisikan dalam kelas induk. Secara visual, hubungan inheritansi ditunjukan menggunakan tanda panah kosong, dengan ujung panah berada pada kelas induk. Gambar 1.14 menunjukan hubungan inheritansi untuk contoh yang sudah dibahas di awal bab ini.
Inheritansi membentuk hubungan “adalah (sebuah)”. Dalam contoh di atas, dapat dikatakan:
"SepedaMotor adalah (sebuah) KendaraanDarat"
"Mobil adalah (sebuah) KendaraanDarat"
Sebagai programmer, kita dapat membuat dan melengkapi kelas turunan dengan variabel dan metode tambahan, atau dengan memodifikasi metode dan variabel “warisan”.
Dalam Java, inheritansi dibentuk menggunakan kata kunci extends
. Misalnya:
class Mobil extends KendaraanDarat { /* body */ }
Overriding dan Overloading
Kelas turunan dapat memodifikasi atau mendefinisikan ulang metode “warisan” sesuai dengan kepentingan subjektif. Proses pendefinisian ulang ini dikenal sebagai method overriding. Perbedaan metode yang ditulis ulang dengan metode asalnya adalah hanya pada badan kelas, sedangkan header harus tetap identik. Jika sebuah metode didefinisikan ulang, tipe objek yang memanggil akan menentukan versi metode yang akan dijalankan. Jika pada proses pendefinisian ulang, diperlukan pemanggilan metode asal di kelas induk, maka hal ini dapat dilakukan melalui kata kunci super
. Overriding dapat dihindari dengan mendeklarasikan sebuah metode menggunakan modifier final
.
Overloading juga merupakan proses mengasosiasikan sebuah nama metode dengan beberapa definisi yang berbeda. Hanya saja, header atau signatur dari metode harus berbeda untuk tiap definisi. Signatur merupakan kombinasi yang unik dari jumlah, tipe dan urutan parameter. Nilai balik dari sebuah metode bukan merupakan bagian dari signatur. Ini berarti metode-metode yang di-overloaded tidak bisa hanya berbeda dari nilai baliknya. Overloading biasanya dilakukan pada konstruktor, sehingga memungkinkan pembentukan objek baru melalui beberapa cara.
Beberapa karakteristik dan perbedaan antara overriding dan overloading diberikan dalam Tabel 1.6. Tabel 1.6. Perbedaan Overriding dan Overloading
Iterator
Iterator adalah sebuah objek yang mendukung dan mempermudah pengolahan sekumpulan item atau koleksi objek. Iterator menyediakan bermacam servis untuk „bergerak“ dari satu item ke item yang lain, juga memprosesnya jika diperlukan. Sebuah objek Iterator mempunyai metode hasNext() yang akan memberikan nilai balik true, bila masih ada setidaknya satu item yang belum diproses. Metode next() memberikan nilai balik berupa referensi ke objek berikutnya, yang belum diproses. Objek Iterator didefinisikan sebagai objek yang mengimplementasikan interface Iterator.
Dengan menggunakan objek Iterator, sebuah varian dari pernyataan for dapat menyederhanakan pemrosesan repetitif dari sekumpulan objek. Jika DaftarMobil merupakan sebuah Iterator untuk sekumpulan objek Mobil, maka pernyataan berikut akan menjalankan metode cetakPemilik() untuk setiap objek:
for(Mobil m : DaftarMobil) m.cetakPemilik();
Pernyataan for di atas dapat dibaca sebagai “untuk setiap Mobil dalam DaftarMobil panggil metode cetakPemilik()”. Karena pernyataan ini akan memproses „setiap“ objek, versi iterator untuk pernyataan for sering disebut sebagai pernyataan foreach.
Paket dan Pustaka Kelas
Pustaka kelas (class library) adalah kumpulan atau koleksi kelas-kelas yang berguna dan dapat kita gunakan untuk menyusun program. Pustaka bisa kita buat sendiri, dikembangkan oleh pihak ketiga atau dibuat oleh pengembang Java sebagai bagian dari platform standar. Pustaka kelas standar yang telah merupakan bagian dari paket distribusi Java dikenal sebagai Java Standard Class Library. Kelas-kelas elementer yang sering digunakan, seperti System atau String merupakan bagian dari pustaka standar ini.
Kelas-kelas dalam pustaka standar Java, dikelompokan kedalam paket (package). Beberapa paket dalam pustaka standar dicantumkan dalam Tabel 1.7. Tabel 1.7. Beberapa paket dalam pustaka standard Java (base library)
Menggunakan Pustaka
Untuk mengakses sebuah kelas dari paket tertentu dapat menggunakan fully qualified name, misalnya:
java.util.Scanner
Sebagai alternatif, bisa dengan melakukan import secara eksplisit untuk kelas yang bersangkutan. Sehingga pada badan program, kita tinggal menggunakan nama kelasnya saja:
import java.util.Scanner;
Untuk mengimport semua kelas dalam sebuah paket, dapat digunakan karakter * (wildcard):
import java.util.*;
Paket java.lang dan java.util
Paket java.lang dan java.util termasuk kedalam pustaka basis yang menyediakan kelas-kelas serta interface untuk mendukung fungsionalitas mendasar dari Java platform. Paket java.lang merupakan paket yang esensial dalam bahasa Java. Semua kelas dari paket java.lang diimport secara otomatis ke semua program, seolah-olah dalam setiap program terdapat pernyataan:
import java.lang.*;
Sehingga kita tidak perlu mengimport kelas seperti System dan String secara eksplisit, karena kedua kelas ini merupakan bagian dari paket java.lang.
Kelas lain yang termasuk kedalam paket java.lang adalah kelas Math, yang antara lain berisi metode-metode untuk melakukan berbagai operasi matematis. Metode-metode ini diimplementasikan sebagai metode statik (static/class method) sehingga dapat dipanggil langsung melalui nama kelasnya. Dengan kata lain, pemanggilan metode statik tidak memerlukan inisiasi objek. Misalnya:
value = Math.cos(90) + Math.sqrt(delta);
Paket java.util memuat kelas-kelas seperti Scanner dan Random. Kelas Scanner berisi berbagai macam fungsi untuk user input . Sedangkan kelas Random dapat dipakai untuk menggenerasikan bilangan pseudo-random.
Selain itu, java.util juga berisi kelas-kelas dari Collections Framework yang berguna untuk memproses kumpulan atau koleksi objek-objek secara konsisten, tidak tergantung pada detil representasi tiap objek.
Paket-Paket Lain
Selain java.lang dan java.util, masih banyak paket-paket lain yang merupakan bagian dari pustaka kelas standar Java. Berbeda dengan java.lang dan java.util, sebagian besar paket-paket dalam pustaka standar mempunyai fungsi yang lebih khusus. Termasuk didalamnya paket java.net yang menyediakan fungsionalitas komunikasi di jaringan atau paket java.applet yang dapat digunakan untuk membuat applet, sebuah aplikasi yang berjalan diatas browser.
Untuk keperluan insidental, spesifik untuk paket tertentu yang mungkin muncul dalam pembahasan di bab-bab berikut, pembaca dipersilahkan untuk membuka dokumentasi dan API (Application Programming Interface) dari paket yang terkait.
Lisensi
CC Attribution-NonCommercial-NoDerivatives (Lisensi)