Sunday, December 18, 2016

Bab 11. Java Teori dan Implementasi



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.

Gambar 11.2 Metode dipanggil secara dinamis terikat

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;
}

Gambar 11.3 Suatu ArrayList menyimpan objek dalam jumlah tak terbatas.


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