Bab.
11 Pewarisan dan Polimorfisme
11.1 Introduksi
Pemrograman berorientasi objek
mengijinkan Anda untuk menderivasi kela-kelas baru dari kelas-kelas yang sudah
ada. Ini dikenal dengan pewarisan. Pewarisan merupakan fitur yang penting dan
berguna dalam JAVA untuk mendaur-ulang kode. Dimisalkan bahwa Anda akan
mendefinisikan kelas untuk memodelkan lingkaran, persegi-panjang, dan segitiga.
Ketiga kelas tersebut memiliki beberapa kesamaan yang bisa saling berbagi.
Apakah cara terbaik untuk mendesain ketiga kelas itu sehingga dapat menghindari
keberlebihan (redundancy) dan membuat
kode menjadi lebih mudah dipahami dan dipelihara? Jawabannya adalah menggunakan
pewarisan.
11.2 Superkelas dan Subkelas
Anda menggunakan kelas untuk
memodelkan objek-objek yang bertipe sama. Kelas-kelas yang berbeda bisa jadi
memiliki kesamaan watak, yang dapat digeneralisasi di dalam suatu kelas
sehingga bisa dibagi oleh kelas-kelas lain. Pewarisan memampukan Anda untuk mendefinisikan
suatu kelas umum dan selanjutnya memperluasnya menjadi kelas-kelas yang lebih
spesifik. Kelas-kelas spesifik ini mewarisi bidang data dan metode dari kelas
umum tersebut.
Mari kita pikirkan tentang
objek-objek geometrik. Dimisalkan Anda akan mendesain beberapa kelas untuk
memodelkan objek-objek geometrik seperti lingkaran dan persegi-panjang.
Objek-objek geometrik memiliki beberapa kesamaan, seperti digambar dengan warna
tertentu, terisi warna, atau tidak terisi warna. Jadi, suatu kelas umum bernama
ObjekGeometrik dapat digunakan untuk
memodelkan semua objek-objek geometrik. Kelas ini memuat bidang data warna dan terisi dan beberapa metode dapat
dan tetapkan. Diasumsikan pula bahwa
kelas ini juga memuat bidang data tanggalDiciptakan
dan metode dapatTanggalDiciptakan()
dan keString(). Metode keString() mengembalikan suatu
representasi string atas objek-objek.
Karena lingkaran adalah suatu
jenis spesial dari objek geometri, lingkaran memiliki kesamaan bidang data dan
metode dengan objek-objek geometri yang lain. Oleh karena itu, maka masuk akal
bila kelas Lingkaran mewarisi kelas ObjekGeometri. Dengan alur pikiran yang
sama, kelas PersegiPanjang dapat
pula dideklarasikan untuk mewarisi kelas ObjekGeometri.
Gambar 11.1 menunjukkan relasi antara ketiga kelas ini. Arah panah yang
menunjuk kepada superkelas digunakan untuk menandai relasi pewarisan antara dua
kelas yang terlibat.
Gambar
11.1
Kelas ObjekGeometri adalah
superkelas untuk Lingkaran dan PersegiPanjang
Dalam terminologi JAVA, suatu
kelas C1 mewarisi dari kelas lain C2 disebut dengan subkelas, dan C2
dikatakan sebagai superkelas. Suatu
superkelas disebut pula dengan kelas parent
atau kelas basis, dan suatu subkelas
disebut pula dengan kelas child atau
kelas terderivasi. Suatu subkelas
mewarisi dari superkelas bidang-bidang data dan metode-metode yang dapat
diakses dan diperkenankan untuk menambah bidang-bidang data dan metode-metode
baru.
Kelas Lingkaran mewarisi dari kelas ObjekGeometri
semua bidang-bidang data dan metode-metode yang dapat diakses. Dan kelas Lingkaran juga memiliki bidang data
sendiri radius dan beberapa metode
sendiri dapat dan tetapkan. Kelas ini juga memuat metode dapatLuas(), dapatKeliling(), dan dapatDiameter()
untuk secara berturut-turut mengembalikan luas, lingkaran, dan diameter suatu
lingkaran.
Kelas PersegiPanjang mewarisi dari kelas ObjekGeometri semua bidang-bidang data dan metode-metode yang dapat
diakses. Dan kelas PersegiPanjang
juga memiliki bidang data sendiri lebar dan tinggi dan beberapa metode sendiri dapat dan tetapkan. Kelas ini juga memuat metode dapatLuas(), dan dapatKeliling()
untuk secara berturut-turut mengembalikan luas dan lingkaran suatu
persegi-panjang.
Kelas ObjekGeometri, Lingkaran,
dan PersegiPanjang ditampilkan pada
kode11.1, kode11.2, dan kode11.3.
Kode11.1 ObjekGeometri1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
public class ObjekGeometri1 {
private
String warna = "putih";
private
boolean terisi;
private
java.util.Date tanggalDiciptakan;
/**
Menciptakan suatu objek geometri default */
public
ObjekGeometri1() {
tanggalDiciptakan = new
java.util.Date();
}
/**
Menciptakan suatu objek geometri dengan warna dan
*
nilai terisi tertentu */
public
ObjekGeometri1(String warna, boolean terisi) {
tanggalDiciptakan = new
java.util.Date();
this.warna
= warna;
this.terisi
= terisi;
}
/**
Mengembalikan warna */
public
String dapatWarna() {
return
warna;
}
/**
Menetapkan suatu warna baru */
public
void dapatWarna(String warna) {
this.warna
= warna;
}
/**
Mengembalikan terisi. Karena terisi adalah suatu boolean,
metode
dapat dinamai apaTerisi */
public
boolean apaTerisi() {
return
terisi;
}
/**
Menetapkan suatu nilai terisi yang baru */
public
void tetapkanTerisi(boolean terisi) {
this.terisi
= terisi;
}
/**
Mendapatkan tanggalDiciptakan */
public
java.util.Date dapatTanggalDiciptakan() {
return
tanggalDiciptakan;
}
/**
Mengembalikan suatu representasi string atas objek ini */
public
String keString() {
return
"diciptakan
pada " + tanggalDiciptakan + "\nwarna: " + warna +
"
dan nilai terisi: " + terisi;
}
}
|
Kode11.2 Lingkaran4.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
|
public class Lingkaran4 extends ObjekGeometri1{
private
double radius;
public
Lingkaran4() {
}
public
Lingkaran4 (double radius) {
this.radius
= radius;
}
public
Lingkaran4(double radius, String warna, boolean terisi) {
this.radius
= radius;
dapatWarna(warna);
tetapkanTerisi(terisi);
}
/**
Mengembalikan radius */
public
double dapatRadius() {
return
radius;
}
/**
Menetapkan suatu radius baru */
public
void tetapkanRadius(double radius) {
this.radius
= radius;
}
/**
Mengembalikan luas */
public
double dapatLuas() {
return
radius * radius * Math.PI;
}
/**
Mengembalikan diameter */
public
double dapatDiameter() {
return
2 * radius;
}
/**
Mengembalikan keliling */
public
double dapatKeliling() {
return
2 * radius * Math.PI;
}
/*
Menampilkan informasi lingkaran */
public
void tampilLingkaran() {
System.out.println("Lingkaran diciptakan
pada "+ dapatTanggalDiciptakan()
+ " dan radiusnya adalah
" + radius);
}
}
|
Kelas Lingkaran
mewarisi kelas ObjekGeometri
(kode11.2) menggunakan sintaks berikut ini:
Katakunci extends (baris 1) memberitahukan kompiler bahwa kelas Lingkaran mewarisi kelas ObjekGeometri, jadi mewarisi dapatWarna, tetapkanWarna, apaTerisi,
tetapkanTerisi, dan keString.
Konstruktor teroverload Lingkaran(double radius, string warna,
boolean terisi) diimplementasikan dengan memanggil dua metode publik tetapkanWarna dan tetapkanTerisi. Kedua metode tersebut didefinisikan di dalam kelas
basis ObjekGeometri dan diwarisi
oleh kelas terderivasi Lingkaran.
Anda mungkin saja terpancing untuk
menggunakan dua bidang data warna
dan terisi secara langsung di dalam
konstruktor sebagai berikut:
public
Lingkaran4(double
radius, String warna, boolean terisi) {
this.radius = radius;
this. warna = warna; // Salah
this. terisi = terisi; // Salah
}
Hal ini salah, karena bidang data privat warna dan terisi di dalam kelas ObjekGeometri
tidak dapat diakses dari sembarang kelas kecuali dari kelas ObjekGeometri itu sendiri. Satu-satunya
cara untuk membaca dan memodifikasi warna
dan terisi adalah melalui
metode-metode dapat dan tetapkan dalam kelas ObjekGeometri.
Kelas PersegiPanjang
mewarisi kelas ObjekGeometri
(kode11.3) menggunakan sintaks berikut ini:
Katakunci extends (baris 1) memberitahukan kompiler bahwa kelas PersegiPanjang mewarisi kelas ObjekGeometri, jadi mewarisi dapatWarna, tetapkanWarna, apaTerisi,
tetapkanTerisi, dan keString.
Kode11.3 PersegiPanjang1.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
public class PersegiPanjang1 extends ObjekGeometri1 {
private
double lebar;
private
double tinggi;
public
PersegiPanjang1() {
}
public
PersegiPanjang1(double lebar, double tinggi) {
this.lebar
= lebar;
this.tinggi
= tinggi;
}
public
PersegiPanjang1(double lebar, double tinggi, String warna,
boolean
terisi) {
this.lebar
= lebar;
this.tinggi
= tinggi;
dapatWarna(warna);
tetapkanTerisi(terisi);
}
/**
Mengembalikan lebar */
public
double dapatLebar() {
return
lebar;
}
/**
Menetapkan suatu lebar baru */
public
void dapatLebar(double lebar) {
this.lebar
= lebar;
}
/**
Mengembalikan tinggi */
public
double dapatTinggi() {
return
tinggi;
}
/**
Menetapkan suatu tinggi baru */
public
void tetapkanTinggi(double tinggi) {
this.tinggi
= tinggi;
}
/**
Mengembalikan luas */
public
double dapatLuas() {
return
lebar * tinggi;
}
/**
Mengembalikan keliling persegi-panjang */
public
double dapatKeliling() {
return
2 * (lebar + tinggi);
}
}
|
Program pada kode11.4 menciptakan objek Lingkaran dan PersegiPanjang dan memanggil beberapa metode pada objek ini. Metode
keString() diwariskan dari kelas ObjekGeometri dan dipanggil dari suatu
objek Lingkaran (baris 4) dan dari
suatu objek PersegiPanjang (baris
10).
Kode11.4 UjiLingkaranPersegiPanjang.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class UjiLingkaranPersegiPanjang {
public
static void main(String[] args) {
Lingkaran4 lingkaran = new
Lingkaran4(1);
System.out.println("Lingkaran
"+ lingkaran.keString());
System.out.println("Radius
sebesar "+ lingkaran.dapatRadius());
System.out.println("Luas
sebesar "+ lingkaran.dapatLuas());
System.out.println("Diameter
sebesar "+ lingkaran.dapatDiameter());
PersegiPanjang1 persegipanjang =
new PersegiPanjang1(2, 4);
System.out.println("\nPersegi-panjang"+ persegipanjang.keString());
System.out.println("Luas
sebesar "+ persegipanjang.dapatLuas());
System.out.println("Keliling
sebesar " +
persegipanjang.dapatKeliling());
}
}
|
Keluaran
Lingkaran
diciptakan pada Mon Nov 12 21:26:48 ICT 2012
warna: putih
dan nilai terisi: false
Radius
sebesar 1.0
Luas sebesar
3.141592653589793
Diameter
sebesar 2.0
Persegi-panjang
diciptakan pada Mon Nov 12 21:26:48 ICT 2012
warna: putih
dan nilai terisi: false
Luas sebesar
8.0
Keliling
sebesar 12.0
Beberapa poin yang terkait pewarisan ini
patut dicatat:
- Tidak seperti interpretasi konvensional, suatu subkelas bukanlah himpunan bagian dari superkelasnya. Pada kenyataannya, subkelas memuat lebih banyak informasi dan metode daripada superkelasnya.
- Bidang data privat dalam suatu superkelas tidak dapat diakses dari luar kelas. Oleh karena itu, tidak dapat diakses langsung dari subkelas. Bidang data privat hanya bisa diakses melalui aksesor/mutator publik yang didefinisikan di dalam superkelas.
- Pewarisan digunakan untuk memodelkan relasi adalah-suatu. Jangan secara buta menggunakan pewarisan hanya demi kepentingan pendaur-ulangan. Sebagai contoh, sangat tidak masuk akal bila suatu kelas Pohon mewarisi kelas Orang, meskipun keduanya memiliki kesamaan bidang data tinggi dan berat.
- Beberapa bahasa pemrograman mengijinkan Anda untuk menderivasi suatu subkelas dari beberapa superkelas. Kapabilitas ini dikenal dengan pewarisan jamak. Akan tetapi, JAVA tidak mengijinkan pewarisan jamak. Suatu kelas JAVA hanya bisa mewarisi secara langsung dari satu superkelas. Pembatasan ini dikenal dengan pewarisan tunggal. Jika anda menggunakan katakunci extends untuk mendefinisikan suatu subkelas, maka hanya akan ada satu kelas basis bagi kelas terderivasi tersebut.
11.3 Menggunakan Katakunci super
Suatu subkelas mewarisi dari suatu
superkelas bidang data dan metode yang dapat diakses. Apakah subkelas tersebut
mewarisi konstruktor juga? Dapatkah konstruktor superkelas dipanggil dari
subkelas? Bagian ini akan membahas isu-isu tersebut.
Pada bagian 10.4 telah dikenalkan referensi
this, yang menunjuk kepada objek
pemanggil. Katakunci super menunjuk
kepada superkelas dimana di dalamnya terdapat katakunci super. Kegunaan katakunci ini ada dua:
·
Untuk memanggil suatu konstruktor
superkelas.
·
Untuk memanggil suatu metode superkelas.
11.3.1 Memanggil Konstruktor
Superkelas
Sintaks untuk memanggil suatu konstruktor
superkelas adalah
super(), atau super(parameter-parameter);
Statemen super() memanggil konstruktor tanpa-argumen dari superkelas, dan
statemen super(argumen-argumen)
memanggil konstruktor yang memiliki argumen yang sesuai. Statemen super() atau super(argumen-argumen) harus muncul di baris pertama konstruktor
subkelas; ini merupakan satu-satunya cara untuk secara eksplisit memanggil
suatu konstruktor superkelas. Sebagai contoh, baris 11-15 pada kode11.2 dapat
diganti dengan kode berikut ini:
public
Lingkaran4(double
radius, String warna, boolean terisi) {
super(warna, terisi);
this.radius = radius;
}
11.3.2 Rantai Konstruktor
Suatu konstruktor dapat memanggil suatu
konstruktor teroverload atau suatu konstruktor superkelasnya. Jika keduanya
tidak dipanggil, maka kompiler secara otomatis akan menempatkan super() sebagai statemen pertama di
dalam konstruktor. Sebagai contoh,
Pada semua kasus, menciptakan suatu instans
dari suatu kelas akan menyebabkan pemanggilan konstruktor dari semua superkelas
pada rantai pewarisan. Ketika menciptakan objek dari suatu subkelas,
konstruktor subkelas, sebelum melaksanakan tugas, pertama-tama memanggil
konstruktor superkelasnya. Jika superkelas tersebut diderivasi dari suatu kelas
lain, maka konstruktor superkelas, sebelum melaksanakan tugas, akan memanggil
konstruktor kelas basisnya. Proses ini berlanjut sampai konstruktor terakhir di
sepanjang hirarki pewarisan dipanggil. Hal ini disebut dengan rantai konstruktor. Perhatikan kode
berikut ini:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class Fakultas
extends Karyawan{
public
static void main(String[] args) {
new Fakultas();
}
public Fakultas(){
System.out.println("(4)
Melaksanakan tugasnya Fakultas");
}
}
class Karyawan
extends Orang{
public Karyawan(){
this("(2)
Memanggil konstruktor teroverload kelas Karyawan");
System.out.println("(3)
Melaksanakan tugasnya Karyawan ");
}
public Karyawan(String s){
System.out.println(s);
}
}
class Orang {
public Orang(){
System.out.println("(1)
Melakukan tugasnya Orang");
}
}
|
Keluaran
(1)
Melakukan tugasnya Orang
(2)
Memanggil konstruktor teroverload kelas Karyawan
(3)
Melaksanakan tugasnya Karyawan
(4)
Melaksanakan tugasnya Fakultas
Program menghasilkan keluaran di atas.
Mengapa? Pada baris 3, new Fakultas() memanggil
konstruktor tanpa-argumen kelas Fakultas.
Karena Fakultas adalah subkelas dari
Karyawan, maka konstruktor
tanpa-argumen kelas Karyawan
dipanggil sebelum sembarang statemen di dalam konstruktor kelas Fakultas dieksekusi. Karena Karyawan adalah subkelas dari Orang, maka konstruktor tanpa-argumen
kelas Orang dipanggil sebelum
sembarang statemen di dalam konstruktor kelas Karyawan dieksekusi. Proses ini diilustrasikan berikut ini:
11.3.3 Memanggil Metode Superkelas
Katakunci super dapat pula dipakai untuk menunjuk kepada suatu metode selain
konstruktor di dalam superkelas. Sintaksnya adalah
super.metode(parameter-parameter);
Anda dapat menulis-ulang metode tampilLingkaran() dalam kelas Lingkaran menjadi:
public void tampilLingkaran() {
System.out.println("Lingkaran
diciptakan pada " +
super.dapatTanggalDiciptakan() + " dan radiusnya adalah " +
radius);
}
11.4 Overriding Metode
Suatu subkelas mewarisi metode-metode dari
suatu superkelas. Kadang-kala penting bagi subkelas untuk memodifikasi
implementasi suatu metode yang didefinisikan di dalam superkelas. Hal ini
dikatakan dengan overriding metode.
Metode keString
dalam kelas ObjekGeometri
mengembalikan suatu representasi string untuk suatu objek geometri. Metode ini
dapat dioverride untuk mengembalikan
representasi string untuk suatu lingkaran. Untuk melakukannya, tambahkan metode
baru berikut ini dalam kode11.2, Lingkaran4.java:
public
class Lingkaran4
extends ObjekGeometri1 {
// Metode-metode lain diabaikan
/** Mengoverride metode keString yang
didefinisikan dalam ObjekGeometri */
public String keString() {
return super.keString() + "\nradius sebesar
" + radius;
}
}
Metode keString()
didefinisikan dalam kelas ObjekGeometri
dan dimodifikasi dalam kelas Lingkaran.
Kedua metode dapat digunakan dalam kelas Lingkaran.
Untuk memanggil metode keString() yang
didefinisikan dalam kelas ObjekGeometri
dari kelas Lingkaran, gunakan super.keString().
Beberapa poin patut dicatat di sini:
·
Suatu metode instans dapat dioverride
hanya jika metode itu dapat diakses. Jadi, suatu metode privat tidak bisa
dioverride, karena hanya bisa diakses dari dalam kelasnya sendiri. Jika suatu metode
di dalam suatu subkelas merupakan privat dalam superkelas, maka kedua metode
itu tidak ada hubungan sama sekali.
·
Sama seperti metode instans, metode
statik dapat diwariskan. Akan tetapi, metode statik tidak bisa dioverride. Jika
suatu metode statik yang didefinisikan di dalam superkelas didefinisikan-ulang
dalam suatu subkelas, maka metode yang didefinisikan dalam superkelas menjadi
tersembunyi. Metod statik yang tersembunyi dapat dipanggil dengan sintaks NamaSuperKelas.namaMetodeStatik.
11.5 Overriding Versus Overloading
Anda telah belajar tentang overloading pada
bagian 5.8. Overloading berarti mendefinisikan beberapa metode yang memiliki
nama sama tetapi dengan sidik yang berbeda. Overriding berarti menyediakan
suatu implementasi baru untuk suatu metode di dalam subkelas. Metode tersebut
sebelumnya telah didefinisikan di dalam superkelas.
Untuk mengoverride suatu metode, metode
tersebut harus didefinisikan dalam subkelas menggunakan sidik yang sama dan
tipe nilai balik yang sama.
Berikut diberikan suatu contoh untuk
membedakan antara overriding dengan overloading. Pada (a), metode p(double i) dalam kelas A mengoverride metode yang sama yang
didefinisikan dalam kelas B. Pada
(b), kelas B memiliki dua metode
teroverload p(double i) dan p(int i). Metode p(double i) diwarisi dari kelas B.
Ketika Anda menjalankan kelas Test pada (a), kedua a.p(10) dan a.p(10.0) memanggil metode p(double
i) yang didefinisikan dalam kelas A
dan menampilkan 10.0. Ketika Anda
menjalankan kelas Test pada (b), a.p(10) memanggil metode p(int i) yang didefinisikan dalam kelas
B untuk menampilkan 20 dan a.p(10.0) memanggil metode p(double
i) yang didefinisikan dalam kelas A
dan menampilkan 10.0.
11.6 Polimorfisme
Tiga pilar pemrograman berorientasi objek
adalah enkapsulasi, pewarisan, dan polimorfisme. Anda telah belajar enkapsulasi
dan pewarisan. Bagian ini akan mengenalkan polimorfisme.
Ada dua istilah penting: subtipe dan
supertipe. Suatu kelas mendefinisikan suatu tipe. Suatu tipe yang didefinisikan
oleh suatu subkelas disebut dengan subtipe dan suatu tipe yang didefinisikan
oleh suatu superkelas disebut dengan supertipe. Jadi, Anda bisa mengatakan
bahwa Lingkaran adalah subtipe dari ObjekGeometri dan ObjekGeometri merupakan supertipe untuk Lingkaran.
Relasi pewarisan memampukan suatu subkelas
mewarisi fitur-fitur dari superkelasnya dengan tambahan fitur-fitur baru. Suatu
subkelas merupakan spesialisasi dari superkelasnya; setiap instans dari
subkelas juga merupakan instans dari superkelasnya, tetapi tidak untuk
sebaliknya. Sebagai contoh, setiap lingkaran merupakan suatu objek geometri,
tetapi tidak setiap objek geometri adalah lingkaran. Oleh karena itu, Anda bisa
melewatkan suatu instans dari subkelas kepada suatu parameter dengan tipe
superkelas (supertipe).
Kode11.5 DemoPolimorfisme.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
public class DemoPolimorfisme {
/**
Metode utama */
public
static void main(String[] args) {
//
Menampilkan watak lingkaran dan persegi-panjang
tampilObjek(new Lingkaran4(1,
"merah", false));
tampilObjek(new PersegiPanjang1(1,
1, "hitam", true));
}
/**
Menampilkan watak objek geometri */
public
static void tampilObjek(ObjekGeometri1
objek){
System.out.println("Diciptakan pada " +
objek.dapatTanggalDiciptakan()
+ ". Warna adalah " +
objek.dapatWarna());
}
}
|
Keluaran
Diciptakan
pada Tue Nov 13 00:52:16 ICT 2012. Warna adalah merah
Diciptakan
pada Tue Nov 13 00:52:16 ICT 2012. Warna adalah hitam
Metode tampilObjek
(baris 10) mengambil suatu parameter bertipe ObjekGeometri. Anda dapat memanggil tampilObjek dengan melewatkan
sembarang instans dari ObjekGeometri (misalnya, new Lingkaran4(1, "merah", false) dan new
PersegiPanjang1(1, 1, "hitam", true) pada baris 5-6). Suatu objek
subkelas dapat digunakan dimana saja objek superkelasnya digunakan. Hal ini
dikenal dengan polimorfisme. Dengan
kalimat sederhana dikatakan bahwa polimorfisme berarti bahwa suatu variabel
supertipe dapat menunjuk kepada suatu objek subtipe.
11.7 Pengikatan Dinamis
Pengikatan dinamis bekerja sebagai berikut:
Dimisalkan suatu objek o merupakan
suatu instans dari kelas
,
, ...,
, dan
,
dimana
adalah subkelas dari
,
adalah subkelas dari
, ...,
adalah subkelas dari
,
seperti ditunjukkan pada Gambar 11.2. Jadi,
merupakan kelas yang paling umum dan
merupakan kelas yang paling spesifik. Dalam
JAVA,
adalah kelas Object. Jika o memanggil suatu metode p,
maka JVM akan mencari implementasi metode p
dalam urutan
,
, ...,
, dan
,
sampai implementasi tersebut ditemukan. Begitu implementasi yang dicari
ditemukan, pencarian berhenti dan implementasi yang pertama ditemukanlah yang
dipanggil.
Kode11.6 memberikan contoh untuk
mengilutrasikan pengikatan dinamis.
Kode11.6 DemoPengikatanDinamis.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
|
public class DemoPengikatanDinamis {
public
static void main(String[] args) {
m(new MahasiswaPascaSarjana());
m(new
Mahasiswa());
m(new
Orang());
m(new
Object());
}
public
static void m(Object x){
System.out.println(x.toString());
}
}
class MahasiswaPascaSarjana
extends Mahasiswa{
}
class Mahasiswa
extends Orang{
public
String toString(){
return
"Mahasiswa";
}
}
class Orang
extends Object{
public
String toString(){
return
"Orang";
}
}
|
Keluaran
Mahasiswa
Mahasiswa
Orang
java.lang.Object@42e816
Metode m
(baris 9) mengambil suatu parameter bertipe Object. Anda dapat memanggil m dengan sembarang objek (yaitu, new MahasiswaPascaSarjana(), new Mahasiswa(), new Orang(), dan new
Object()) pada baris 3-6.
Ketika metode m(Object x) dieksekusi, argumen x dari metode toString
dipanggil. x bisa jadi instans dari MahasiswaPascaSarjana, Mahasiswa, Orang, atau
Object. Masing-masing kelas MahasiswaPascaSarjana, Mahasiswa, Orang, dan
Object memiliki implementasi
sendirit atas metode toString.
Implementasi mana yang digunakan ditentukan oleh tipe aktual x pada saat runtime.
Memanggil m(new
MahasiswaPascaSarjana()) (baris 3) menyebabkan metode toString() yang didefinisikan dalam kelas Mahasiswa dipanggil.
Memanggil m(new Mahasiswa())
(baris 4) menyebabkan metode toString()
yang didefinisikan dalam kelas Mahasiswa
dipanggil.
Memanggil m(new Orang()) (baris 5)
menyebabkan metode toString() yang
didefinisikan dalam kelas Orang
dipanggil.
Memanggil m(new Object()) (baris
6) menyebabkan metode toString()
yang didefinisikan dalam kelas Object
dipanggil.
11.8 Casting Objek dan Operator
instanceof
Anda telah menggunakan operator casting
untuk mengubah variabel-variabel suatu tipe primitif menjadi tipe primitif yang
lain. Casting dapat pula digunakan untuk mengubah objek dengan suatu tipe kelas
menjadi objek dengan tipe kelas lain, di dalam suatu hirarki pewarisan. Pada
bagian sebelumnya, statemen
m(new Mahasiswa());
menugaskan objek new Mahasiswa() kepada suatu parameter bertipe Object. Statemen tersebut ekivalen dengan
Object
o = new Mahasiswa(); // Casting implisit
m(o);
Statemen Object o = new Mahasiswa(), dikenal sebagai casting implisit,
merupakan hal yang sah karena suatu instans Mahasiswa secara otomatis adalah suatu instans Object.
Seandainya Anda ingin menugaskan referensi
objek o kepada suatu variabel
bertipe Mahasiswa menggunakan
statemen berikut ini:
Mahasiswa b
= o;
Pada kasus ini, error kompilasi terjadi.
Mengapa statemen Object o = new
Mahasiswa() dapat dilakukan sementara Mahasiswa
b = o tidak bisa dilakukan? Alasannya adalah bahwa suatu objek Mahasiswa selalu merupakan suatu
instans Object, tetapi suatu instans
Object belum tentu merupakan suatu
instans Mahasiswa. Meskipun Anda
dapat melihat bahwa o adalah suatu
objek Mahasiswa, kompiler tidak
cukup pintar untuk mengetahuinya. Untuk memberitahu kompiler bahwa o merupakan suatu objek Mahasiswa, gunakan casting eksplisit.
Sintaks yang digunakan sama seperti yang digunakan untuk mengcasting tipe
primitif, tipe objek target diapit oleh sepesang kurung dan ditempatkan sebelum
objek yang akan dicast:
Mahasiswa b
= (Mahasiswa) o; // Casting eksplisit
Adalah hal yang selalu memungkinkan untuk
melakukan casting terhadap instans dari suatu subkelas menjadi suatu variabel
superkelas (yang dikenal dengan upcasting),
karena instans subkelas selalu merupakan instans superkelas. Ketika melakukan
casting terhadap instans dari suatu superkelas menjadi suatu variabel
subkelasnya (yang dikenal dengan downcasting),
casting eksplisit harus digunakan untuk menegaskan tujuan Anda kepada kompiler.
Agar casting berhasil dilakukan, Anda perlu
memastikan bahwa objek yang akan dicast merupakan suatu instans subkelas. Jika
objek superkelas bukan merupakan suatu instans dari subkelas, erro ClassCastException akan terjadi.
Sebagai contoh, jika suatu objek bukan instans dari Mahasiswa, maka objek tersebut tidak bisa dicast menjadi suatu
variabel Mahasiswa. Hal ini bisa
diselesaikan dengan penggunaan operator instanceof:
Object
ObjekKu = new
Lingkaran();
... //
Beberapa baris kode
/**
Melakukan casting jika ObjekKu merupakan suatu instans dari Lingkaran */
if
(ObjekKu instanceof Lingkaran) {
System.out.println("Diameter
lingkaran adalah " +
((Lingkaran) ObjekKu).dapatDiameter());
...
}
Kode11.7 mendemonstrasikan polimorfisme dan
casting. Program menciptakan dua objek (baris 5-6), suatu lingkaran dan suatu
persegi-panjang, dan memanggil metode tampilObjek
untuk menampilkan kedua objek tersebut (baris 9-10). Metode tampilObjek menampilkan luas dan
diameter jika objek adalah suatu lingkaran (baris 15), dan luas jika objek
adalah suatu persegi-panjang (baris 21).
Kode11.7 DemoCasting.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
public class DemoCasting {
/** Main
method */
public
static void main(String[] args) {
//
Menciptakan dan menginisialisasi dua objek
Object
objek1 = new Lingkaran4(1);
Object
objek2 = new PersegiPanjang1(1, 1);
//
Menampilkan lingkaran dan persegi-panjang
tampilObjek(objek1);
tampilObjek(objek2);
}
/**
Metode untuk menampilkan suatu objek */
public
static void tampilObjek(Object
objek){
if(objek instanceof Lingkaran4)
{
System.out.println("Luas
lingkaran adalah " +
((Lingkaran4)objek).dapatLuas());
System.out.println("Diameter
lingkaran adalah " +
((Lingkaran4)objek).dapatDiameter());
}
else
if(objek instanceof
PersegiPanjang1) {
System.out.println("Luas
persegi-panjang adalah " +
((PersegiPanjang1)objek).dapatLuas());
}
}
}
|
Keluaran
Luas
lingkaran adalah 3.141592653589793
Diameter
lingkaran adalah 2.0
Luas
persegi-panjang adalah 1.0
Metode tampilObjek(Object
objek) merupakan contoh pemrograman generik, yang dapat dipanggil dengan
melewatkan sembarang instans dari Object.
Program menggunakan casting implisit untuk
menugaskan suatu objek Lingkaran
kepada objek1 dan suatu objek PersegiPanjang kepada objek2 (baris 5-6), kemudian memanggil
metode tampilObjek() untuk
menampilkan informasi pada kedua objek tersebut (baris 9-10).
Di dalam metode tampilObjek() (baris 14-25), casting eksplisit digunakan untuk
mengcast objek Lingkaran jika objek
merupakan suatu instans Lingkaran,
dan metode dapatLuas() dan dapatDiameter() digunakan untuk
menampilkan luas dan diameter suatu lingkaran.
Casting bisa dilakukan hanya jika objek
sumber merupakan suatu instans dari kelas target. Program menggunakan operator instanceof untuk memastikan bahwa objek
sumber merupakan suatu instans dari kelas target sebelum melakukan suatu
casting (baris 15).
Casting eksplisit menjadi Lingkaran (baris 17, 19) dan menjadi PersegiPanjang (baris 23) perlu
dilakukan karena metode dapatLuas
dan dapatDiameter tidak tersedia di
dalam kelas Object.
11.9 Metode equals Pada Kelas
Object
Metode lain yang didefinisikan di dalam
kelas Object adalah equals. Sidiknya adalah
public
boolean equals(Object o)
Metode ini menguji apakah dua objek sama.
Sintaks untuk memanggilnya adalah
objek1.equals(objek2);
Implementasi default metode equals di dalam kelas Object adalah
public
boolean equals(Object
obj) {
return (this == obj);
}
Implementasi memeriksa apakah dua variabel
referensi menunjuk kepada objek yang sama menggunakan operator ==. Anda harus mengoverride
implementasi ini di dalam kelas Anda agar ditujukan untuk memeriksa apakah dua
objek yang berbeda mempunyai konten yang sama.
Anda telah menggunakan metode equals dalam kelas String pada Bab. 9. Metode itu diwarisi dari kelas Object dan dioverride dalam kelas String untuk memeriksa apakah konten
dua string identik atau tidak. Anda dapat mengoverride metode equals di dalam kelas Lingkaran untuk membandingkan apakah
dua lingkaran memiliki radius yang sama:
public
boolean equals(Object
o) {
if (o instanceof Lingkaran) {
return radius == ((Lingkaran)o).radius;
}
else
return false;
}
11.10 Kelas ArrayList
Sekarang Anda telah siap untuk mempelajari
kelas ArrayList yang dapat dipakai
untuk menyimpan objek. Sebelumnya, Anda telah dapat menciptakan suatu array,
namun setelah array array tersebut diciptakan, ukurannya tetap tidak bisa lagi
diubah. JAVA menyediakan kelas ArrayList
yang dapat digunakan untuk menyimpan objek dalam jumlah yang tidak terbatas.
Gambar 11.3 menampilkan beberapa metode di dalam kelas ArrayList.
Kode11.8 memberikan suatu contoh penggunaan
ArrayList dalam menyimpan beberapa
objek.
Kode11.8 TestArrayList.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
public class TestArrayList {
public
static void main(String[] args) {
//
Menciptakan suatu list untuk menyimpan nama-nama kota
java.util.ArrayList listKota = new
java.util.ArrayList();
//
Menambahkan beberapa kota dalam list
listKota.add("Klaten");
//
listKota sekarang memuat [Klaten]
listKota.add("Balige");
//
listKota sekarang memuat [Klaten, Balige]
listKota.add("Mataram");
//
listKota sekarang memuat [Klaten, Balige, Mataram]
listKota.add("Yogyakarta");
//
listKota sekarang memuat [Klaten, Balige, Mataram, Yogyakarta]
listKota.add("Siantar");
//
memuat [Klaten, Balige, Mataram, Yogyakarta, Siantar]
listKota.add("Tarabunga");
//
memuat [Klaten, Balige, Mataram, Yogyakarta, Siantar, Tarabunga]
System.out.println("Ukuran
list? "+ listKota.size());
System.out.println("APakah
Klaten ada dalam list? " +
listKota.contains("Klaten"));
System.out.println("Lokasi
Tarabunga dalam list? "
+
listKota.indexOf("Tarabunga"));
System.out.println("Apakah
list kosong? " +
listKota.isEmpty()); //
Menampilkan false
//
Menyisipkan suatu kota baru pada indeks 2
listKota.add(2,
"Solo");
//
memuat [Klaten, Balige, Solo, Mataram, Yogyakarta,
Siantar, Tarabunga]
//
Menghapus suatu kota dari list
listKota.remove("Siantar");
//
memuat [Klaten, Balige, Solo, Mataram, Yogyakarta, Tarabunga]
//
Menghapus suatu kota pada indeks 1
listKota.remove(1);
//
memuat [Klaten, Solo, Mataram, Yogyakarta, Tarabunga]
//
Menampilkan isi list
System.out.println(listKota.toString());
//
Menampilkan isi list dalam urutan terbalik
for
(int i = listKota.size() - 1; i >= 0; i--)
System.out.print(listKota.get(i) + "
");
System.out.println();
//
Menciptakan suatu list untuk menyimpan dua lingkaran
java.util.ArrayList
list = new java.util.ArrayList();
//
Menambahkan dua lingkaran
list.add(new
Lingkaran4(2));
list.add(new
Lingkaran4(3));
//
Menampilkan luas lingkaran pertama di dalam list
System.out.println("Luas
lingkaran pertama? " +
((Lingkaran4)list.get(0)).dapatLuas());
//
Menampilkan luas lingkaran kedua di dalam list
System.out.println("Luas
lingkaran kedua? " +
((Lingkaran4)list.get(1)).dapatLuas());
}
}
|
Keluaran
Ukuran list?
6
APakah
Klaten ada dalam list? true
Lokasi
Tarabunga dalam list? 5
Apakah list
kosong? false
[Klaten,
Solo, Mataram, Yogyakarta, Tarabunga]
Tarabunga
Yogyakarta Mataram Solo Klaten
Luas
lingkaran? 12.566370614359172
Luas
lingkaran? 28.274333882308138
Program menciptakan suatu ArrayList menggunakan konstruktor
tanpa-argumen (baris 4). Metode add
menambahkan sembarang instans dari Object
ke dalam list. Karena String
merupakan subkelas dari Object,
string dapat ditambahkan ke dalam list. Metode add (baris 7-17) menambahkan
suatu objek pada akhir list. Jadi, setelah listKota.add(“Klaten”)
(baris 7) dieksekusi, list berisi
[Klaten]
Setelah listKota.add(“Balige”) (baris 9) dieksekusi, list berisi
[Klaten,
Balige]
Setelah menambahkan Mataram, Yogyakarta,
Siantar, dan Tarabunga (baris 11-17), list akan berisi
[Klaten,
Balige, Mataram, Yogyakarta, Siantar, Tarabunga]
Memanggil size() (baris 20) akan mengembalikan ukuran list, sekarang bernilai
6. Memanggil contains(“Klaten”)
(baris 22) memeriksa apakah objek ada dalam list. Pada kasus ini, metode ini
mengembalikan true, karena Klaten ada dalam list. Memanggil indexOf(“Tarabunga”) (baris 24) akan mengembalikan
indeks objek di dalam list, yang bernilai 1. Jika objek tersebut tidak berada
dalam list, maka akan dikembalikan nilai -1. Metode isEmpty() (baris 26) memeriksa apakah list kosong atau tidak. Nilai
baliknya adalah false, karena list
tidak kosong.
Statemen listKota.add(2, “Solo”) (baris 29) menyisipkan suatu objek ke dalam
list pada indeks tertentu. Setelah statemen ini dieksekusi, list akan berisi
[Klaten,
Balige, Solo, Mataram, Yogyakarta, Siantar, Tarabunga]
Statemen listKota.remove(“Siantar”) (baris 33) menghapus objek dari list.
Setelah statemen ini dieksekusi, list akan berisi
[Klaten,
Balige, Solo, Mataram, Yogyakarta, Tarabunga]
Statemen listKota.remove(1) (baris 37) menghapus objek dari list pada indeks
tertentu. Setelah statemen ini dieksekusi, list akan berisi
[Klaten,
Solo, Mataram, Yogyakarta, Tarabunga]
Statemen pada baris 41 ekivalen dengan
System.out.println(listKota);
Metode toString()
mengembalikan suatu representasi string untuk list dalam format [e0.toString(), e1.toString(), ...,
ek.toString], dimana e1, e2, ..., ek adalah elemen-elemen di dalam list.
Metode get(index)
(baris 45) mengembalikan objek pada indeks tertentu.
Objek-objek ArrayList dapat digunakan seperti array, tetapi terdapat beberapa
perbedaan. Kesamaan dan perbedaannya ditampilkan pada Tabel 11.1.
Tabel 11.1 Kesamaan dan Perbedaan ArrayList
dan Array
Operasi
|
Array
|
ArrayList
|
Menciptakan
suatu array/ArrayList
Mengakses suatu
elemen
Memperbarui
suatu elemen
Mengembalikan
ukuran
Menambahkan
suatu elemen baru
Menyisipkan
suatu elemen baru
Menghapus suatu
elemen
Menghapus suatu
elemen
Menghapus semua
elemen
|
Object[]
a = new Object[10]
a[index]
a[index]
= "Klaten";
a.length
|
ArrayList
list = new ArrayList();
list.get(index);
list.set(index,
" Klaten");
list.size();
list.add("Klaten");
list.add(index,
"Klaten");
list.remove(index);
list.remove(Object);
list.clear();
|
11.11 Perbaikan Pada Kelas
Tumpukan
“Mendesain Suatu Kelas Untuk Tumpukan” pada
bagian 10.9 menyajikan suatu kelas tumpukan untuk menyimpan nilai-nilai int. Pada bagian ini, Anda akan
dikenalkan bagaimana menciptakan suatu kelas tumpukan untuk menyimpan
objek-objek. Anda dapat menggunakan suatu ArrayList
untuk mengimplementasikan tumpukan, seperti ditunjukkan pada kode11.9. Diagram
UML kelas ini ditampilkan pada Gambar 11.4.
Kode11.9 TumpukanKu.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
public class TumpukanKu{
private java.util.ArrayList list =
new java.util.ArrayList();
public boolean apaKosong(){
return
list.isEmpty();
}
public int dapatUkuran(){
return
list.size();
}
public Object intip(){
return
list.get(dapatUkuran() - 1);
}
public Object hapus(){
Object
o = list.get(dapatUkuran() - 1);
list.remove(dapatUkuran()
- 1);
return
o;
}
public void dorong(Object o){
list.add(o);
}
public int cari(Object o){
return
list.lastIndexOf(o);
}
/**
Mengoverride metode toString dalam kelas Object */
public
String toString(){
return
"Tumpukan: " + list.toString();
}
}
|
Gambar 11.4 Kelas TumpukanKu,
yang mengenkapsulasi penyimpanan tumpukan dan yang menyediakan beberapa operasi
untuk memanipulasi tumpukan.
Kelas TumpukanKu
dapat diterapkan seperti kelas TumpukanInteger
pada kode10.7. Di sini disediakan suatu
program uji untuk menggunakan kelas tersebut untuk menciptakan suatu tumpukan,
menyimpan sepuluh integer 0, 1, 2, ..., dan 9, dan menampilkannya dalam urutan
yang terbalik.
1
2
3
4
5
6
7
8
9
10
11
|
public class UjiTumpukanKu {
public static void main(String[]
args) {
TumpukanKu tumpukan = new TumpukanKu();
for (int i = 0; i < 10;
i++)
tumpukan.dorong(i);
while (!tumpukan.apaKosong())
System.out.print(tumpukan.hapus() + "
");
}
}
|
Keluaran
9 8 7 6 5 4
3 2 1 0
11.12 Data dan Metode protected
Sejauh ini Anda telah belajar katakunci public dan private untuk menentukan apakah metode dan bidang data dapat atau
tidak diakses dari luar kelas. Anggota-anggota privat hanya dapat diakses dari
dalam kelas, dan anggota-anggota publik dapat diakses dari sembarang kelas.
Tetapi kadang-kala diinginkan untuk mengijinkan
subkelas dapat mengakses bidang data atau metode yang didefinisikan di dalam
superkelasnya. Untuk melakukannya, Anda bisa menggunakan katakunci protected. Suatu bidang data atau
metode terproteksi di dalam suatu superkelas dapat diakses dari sub-subkelasnya.
Tabel 11.2 menyimpulkan visibilitas dan
aksesibilitas anggota-anggota dalam suatu kelas. Gambar 11.5 mengilustrasikan
visibilitas dan aksesibilats suatu pemodifikasi public, protected,
default (tanpa pemodifikasi), atau private.
Gambar 11.5 Visibilitas pemodifikasi digunakan untuk
mengendalikan metode dan data yang dapat diakses
Tabel 11.2 Visibilitas dan Aksesibilitas Data dan
Metode
Pemodifikasi pada anggota dalam satu
kelas
|
Diakses dari dalam kelas sendiri
|
Diakses dari paket yang sama
|
Diakses dari suatu subkelas
|
Diakses dari paket yang berbeda
|
public
protected
default
private
|
ü
ü
ü
ü
|
ü
ü
ü
--
|
ü
ü
--
--
|
ü
--
--
--
|
Gunakan pemodifikasi private untuk menyembunyikan anggota-anggota kelas secara sempurna
sehingga tidak dapat diakses sama sekali dari luar kelas. Jangan gunakan
pemodifikasi apapun (default) agar mengijinkan anggota-anggota kelas diakses
secara langsung dari sembarang kelas dalam paket yang sama, tetapi tidak dari
paket yang berbeda. Gunakan pemodifikasi protected
untuk memampukan anggota-anggota kelas diakses oleh sub-subkelas dari sembarang
paket atau oleh sembarang kelas dari paket yang sama.
Kelas Anda dapat digunakan dengan dua cara
ini: untuk menciptakan instans kelas, dan untuk mendefinisikan sub-subkelas
dengan mewarisi superkelas. Jadikan anggota-anggota kelas menjadi private jika tidak dimaksudkan untuk
digunakan dari luar kelas. Jadikan anggota-anggota kelas menjadi public jika dimaksudkan untuk pengguna
kelas. Jadikan anggota-anggota kelas menjadi protected jika dimaksudkan untuk sub-subkelas, tetapi tidak untuk
pengguna kelas.
No comments:
Post a Comment