Friday, March 16, 2018

6. Lebih Lanjut Dengan Kelas dan Metode Bagian 2



Lebih Detil Dengan Pelewatan Argumen
Secara umum, ada dua cara bagaimana bahasa pemrograman melewatkan argumen kepada metode. Cara pertama dinamakan pelewatan nilai. Pendekatan ini menyalin nilai argumen ke parameter pada definisi metode. Oleh karena itu, perubahan yang dilakukan pada parameter tidak berpengaruh pada argumen. Cara kedua adalah melewatkan dengan referensi. Pada pendekatan ini, sebuah referensi ke argumen (bukan nilai dari argumen) dilewatkan kepada parameter. Di dalam metode, referensi ini dipakai untuk mengakses argumen aktual yang ditetapkan pada pemanggilan metode. Ini berarti bahwa perubahan yang dilakukan pada parameter akan berpengaruh pada argumen yang dipakai pada pemanggilan metode. Seperti yang akan Anda lihat, meskipun Java menggunakan pelewatan nilai untuk melewatkan argumen, ada perbedaan yang terjadi ketika tipe data sederhana atau tipe data referensi yang dilewatkan.

Ketika Anda melewatkan sebuah tipe data primitif (sederhana) kepada metode, ia dilewatkan dengan nilai. Jadi, salinan dari argumen diciptakan, dan apa yang terjadi pada parameter yang menerima argumen tidak berpengaruh apapun di luar metode. Sebagai contoh, perhatikan program berikut:

// Tipe data primitif dilewatkan dengan nilai.
class Test {
   void metode(int i, int j) {
      i *= 2;
      j /= 2;
   }
}

public class PelewatanNilai {
   public static void main(String args[]) {
      Test ob = new Test();
  
      int a = 15, b = 20;
      System.out.println("a dan b sebelum pemanggilan metode: " + a + " " + b);
  
      ob.metode(a, b);
      System.out.println("a dan b setelah pemanggilan metode: " + a + " " + b);
   }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

a dan b sebelum pemanggilan metode: 15 20
a dan b setelah pemanggilan metode: 15 20

Seperti yang dapat Anda lihat, operasi-operasi yang terjadi di dalam metode() tidak berpengaruh apapun pada nilai dari a dan b pada pemanggilan metode: nilainya tidak berubah menjadi 30 dan 10.

Ketika Anda melewatkan sebuah objek kepada metode, situasinya berubah drastic, karena objek dilewatkan dengan referensi. Ingat bahwa ketika Anda menciptakan sebuah variabel dengan tipe data kelas, Anda hanya menciptakan sebuah referensi ke objek. Jadi, ketika Anda melewatkan referensi kepada sebuah metode, parameter yang menerimanya akan mereferensi atau menunjuk ke objek sama yang ditunjuk oleh argumen. Perubahan pada metode di dalam metode akan memengaruhi objek yang dipakai sebagai argumen. Sebagai contoh, perhatikan program berikut:

// Objek dilewatkan lewat referensi.
class Test {
   int a, b;

   Test(int i, int j) {
      a = i;
      b = j;
   }

   // melewatkan objek
   void metode(Test o) {
      o.a *= 2;
      o.b /= 2;
   }
}

public class PelewatanReferensi {
   public static void main(String args[]) {
      Test ob = new Test(15, 20);
  
      System.out.println("ob.a dan ob.b sebelum pemanggilan metode: " +
         ob.a + " " + ob.b);
    
      ob.metode(ob);
      
      System.out.println("ob.a dan ob.b setelah pemanggilan metode: " +
         ob.a + " " + ob.b);
   }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

ob.a dan ob.b sebelum pemanggilan metode: 15 20
ob.a dan ob.b setelah pemanggilan metode: 30 10

Seperti yang dapat Anda lihat, tindakan di dalam metode() memengaruhi objek yang dipakai sebagai argumen.


Menghasilkan (Nilai Balik) Objek
Metode dapat menghasilkan nilai balik dengan tipe data apapun, termasuk tipe data kelas yang Anda ciptakan. Misalnya, program berikut, metode inkremenSepuluh() menghasilkan sebuah objek dimana nilai dari a lebih besar 10 dari objek pemanggil.
<
// Menghasilkan nilai balik objek.
class Test {
   int a;

   Test(int i) {
      a = i;
   }
   
   Test inkremenSepuluh() {
      Test temp = new Test(a+10);
      return temp;
   }
}

public class NilaiBalikObjek {
   public static void main(String args[]) {
      Test ob1 = new Test(2);
      Test ob2;
  
      ob2 = ob1.inkremenSepuluh();
  
      System.out.println("ob1.a: " + ob1.a);
      System.out.println("ob2.a: " + ob2.a);
  
      ob2 = ob2.inkremenSepuluh();
      System.out.println("ob2.a setelah penambahan kedua: " + ob2.a);
   }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

ob1.a: 2
ob2.a: 12
ob2.a setelah penambahan kedua: 22

Seperti yang Anda lihat, setiap kali inkremenSepuluh() dipanggil, sebuah objek baru diciptakan, dan sebuah referensi ke objek itu dijadikan nilai balik oleh metode pemanggil.


Rekursi
Java mendukung keberadaan rekursi. Rekursi adalah proses pendefinisian berdasarkan dirinya sendiri. Dalam kaitannya dengan pemrograman Java, rekursei merupakan proses dimana sebuah metode dapat memanggil dirinya sendiri.

Contoh klasik dari rekursi adalah perhitungan faktorial. Faktorial dari sebuah nilai N adalah perkalian atas semua bilangan bulat dari 1 sampai N. Misalnya, 3 faktorial adalah 1 x 2 x 3 atau 6. Di sini ditunjukkan bagaimana faktorial dapat dihitung menggunakan metode rekursif:

// Sebuah contoh sederhana dari rekursi.
class Faktorial {
   // ini adalah metode rekursif
   int fakt(int n) {
      int hasil;
   
      if(n==1) return 1;
      hasil = fakt(n-1) * n;
      return hasil;
   }
}

public class Rekursi {
   public static void main(String args[]) {
    Faktorial f = new Faktorial();
  
      System.out.println("Faktorial dari 3 = " + f.fakt(3));
      System.out.println("Faktorial dari 4 = " + f.fakt(4));
      System.out.println("Faktorial dari 5 = " + f.fakt(5));
   }
}

Ketika dijalankan, program ini menghasilkan keluaran:

Faktorial dari 3 = 6
Faktorial dari 4 = 24
Faktorial dari 5 = 120

Jika Anda tidak familiar dengan metode rekursif, maka operasi fakt() tampak membingungkan. Berikut cara kerjanya. Ketika fakt() dipanggil dengan argumen 1, fungsi tersebut menghasilkan 1; sebaliknya, ia menghasilkan perkalian dari fakt(n-1)*n. Untuk mengevaluasi ekspresi ini, fakt() dipanggil dengan n-1. Proses ini berulang sampai n bernilai 1 dan pemanggilan-pemanggilan terhadap metode mulai menghasilkan nilai balik.

Untuk lebih memahami bagaimana metode fakt() bekerja, perhatikan ilustrasi berikut. Ketika Anda menghitung faktorial dari 3, pemanggilan pertama terhadap fakt() akan menyebabkan pemanggilan kedua dengan argumen 2. Pemanggilan ini akan menyebabkan fakt() dipanggil ketiga kalinya dengan argumen 1. Pemanggilan ini akan menghasilkan nilai balik 1, yang kemudian dikalikan dengan 2 (nilai dari n pada pemanggilan kedua). Hasil ini (yaitu 2) kemudian diberikan ke pemanggilan semula dari fakt() dan dikalikan 3 (nilai semula dari n). Ini akan menghasilkan 6.

Ketika menuliskan metode rekursif, Anda memerlukan sebuah statemen if untuk memaksa metode menghasilkan nilai balik tanpa mengeksekusi pemanggilan rekursif. Jika Anda tidak melakukannya, ketika Anda memanggil metode rekursif, maka metode itu tidak menghasilkan apapun. Ini merupakan kejadian error yang umum dijumpai saat bekerja dengan rekursi.

Berikut adalah satu lagi contoh rekursi. Metode rekursif tampilArray() ini menampilkan i elemen pertama pada array nilai:

// Contoh lain dari rekursi.
class UjiRekursi {
   int nilai[];

   UjiRekursi(int i) {
      nilai = new int[i];
   }

   // Menampilkan array secara rekursif
   void tampilArray(int i) {
      if(i==0) return;
      else tampilArray(i-1);
         System.out.println("[" + (i-1) + "] " + nilai[i-1]);
   }
}

public class Rekursi2 {
   public static void main(String args[]) {
      UjiRekursi ob = new UjiRekursi(10);
      int i;
  
      for(i=0; i<10; i++) ob.nilai[i] = i;
         
      ob.tampilArray(10);
   }
}

Ketika dijalankan, program ini menghasilkan keluaran:

[0] 0
[1] 1
[2] 2
[3] 3
[4] 4
[5] 5
[6] 6
[7] 7
[8] 8
[9] 9


Mengenalkan Kendali Akses
Seperti Anda ketahui, enkapsulasi menghubungkan data kelas dengan kode yang memanipulasinya. Namun, enkapsulasi memberikan peranan penting: kendali akses. Melalui enkapsulasi, Anda dapat mengendalikan bagian mana dari sebuah program yang dapat mengakses anggota kelas. Dengan mengendalikan akses, Anda dapat mencegah penyalahgunaan. Misalnya, dengan mengijinkan akses terhadap data hanya melalui metode-metode yang tepat, Anda dapat mencegah penyalahgunaan data. Jadi, ketika diimplementasikan dengan benar, sebuah kelas menciptakan “kotak hitam” yang bisa dipakai, tetapi detil implementasinya tersembunyi oleh pihak pengguna kelas.

Kelas-kelas yang telah disajikan sejauh ini tidak memenuhi tujuan ini. Misalnya, perhatikan kelas Tumpukan di akhir Bab 5. Memang benar metode push() dan pop() memberikan antarmuka terkendali terhadap tumpukan, tetapi antarmuka ini tidak terbaik. Jadi, bagian lain dari program bisa melangkahi metode-metode ini dan mengakses tumpukan secara langsung. Tentu, di tangan yang salah, ini bisa menjadi masalah. Pada bagian ini, Anda akan dikenalkan tentang mekanisme dimana Anda dapat mengendalikan akses terhadap anggota-anggota dari sebuah kelas.

Bagaimana anggota kelas dapat diakses ditentukan oleh pemodifikasi akses yang melekat pada deklarasinya. Java menyediakan banyak pemodifikasi akses. Sejumlah pemodifikasi akses dalam Java adalah public, private, dan protected. Java juga menyediakan level akses default. Pemodifikasi akses protected berlaku ketika melibatkan pewarisan.

Anda akan mulai belajar mendefinisikan public dan private. Ketika sebuah anggota kelas dimodifikasi oleh public, maka anggota kelas tersebut dapat diakses oleh kode manapun. Ketika sebuah anggota kelas ditetapkan sebagai private, maka anggota kelas itu hanya bisa diakses oleh anggota-anggota dari kelasnya. Sekarang Anda dapat mengerti mengapa main() selalu dideklarasikan dengan pemodifikasi public. Metode itu dipanggil oleh kode yang ada di luar program, yaitu sistem run-time Java. Ketika tidak ada pemodifikasi yang digunakan, maka secara default anggota kelas tersebut dipandang dideklarasikan public di dalam paketnya sendiri, tetapi ia tidak bisa diakses di luar paketnya.

Pada kelas-kelas yang telah dikembangkan sejauh ini, semua anggota kelas menggunakan mode akses default: public. Pada banyak aksus, Anda ingin membatasi akses terhadap anggota data kelas, yang hanya bisa diakses melalui metode-metode pada kelas yang sama. Selain itu, ada kalanya juga Anda ingin mendefinisikan metode-metode yang hanya bisa dipakai di dalam kelas, seperti pada contoh ini:

public int i;
private double j;

private int metodeKu(int a, char b) { //...

Dapat dilihat bahwa anggota data kelas i dapat diakses oleh kode dari luar kelas, sedangkan anggota data kelas j, karena dideklarasikan private, hanya bisa diakses oleh metode-metode pada kelas yang sama. Metode metodeKu() juga hanya bisa dipakai di dalam kelas yang sama, karena ia dideklarasikan private. Jadi, metode ini tidak bisa dipanggil dari kode yang ada di luar kelasnya.

Untuk lebih memahami pengaruh dari pemodifikasi akses public dan private, perhatikan program berikut:

/* Program ini mendemonstrasikan perbedaan antara
   public dan private.
*/
class Test {
   int a;          // akses default
   public int b;   // akses public
   private int c;  // akses private 

   // metode untuk mengakses c
   void setc(int i) { // menetapkan nilai c
      c = i;
   }
   
   int getc() { // mendapatkan nilai c
      return c;
   }
}

public class UjiAkses {
   public static void main(String args[]) {
      Test ob = new Test();
  
      // Ini ok, a dan b bisa diakses langsung
      ob.a = 10;
      ob.b = 20;
  
      // Ini tidak boleh karena menyebabkan error
      // ob.c = 100; // Error!
  
      // Anda harus mengakses c lewat metodenya
      ob.setc(100); // OK
      System.out.println("a, b, dan c: " + ob.a + " " +
         ob.b + " " + ob.getc());
   }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

a, b, dan c: 10 20 100


Selanjutnya  >>>

No comments: