Sunday, March 25, 2018

12.Enumerasi dan Autoboxing Bagian Dua



Anda bisa membandingkan nilai ordinal dari dua konstanta pada enumerasi yang sama menggunakan metode compareTo(), yang memiliki bentuk umum berikut:

final int compareTo( tipe-enum e)

Di sini, tipe-enum adalah tipe dari enumerasi, dan e adalah konstanta yang sedang dibandingkan dengan konstanta pemanggil. Ingat, baik konstanta pemanggil maupun e harus dari enumerasi yang sama. Jika konstanta pemanggil memiliki nilai ordinal yang kurang dari nilai ordinal dari e, maka metode compareTo() akan menghasilkan nilai negatif. Jika kedua nilai ordinal sama, maka nol akan dijadikan nilai balik. Jika konstanta pemanggil memiliki nilai ordinal yang lebih besar dari nilai ordinal dari e, maka sebuah nilai positif akan dijadikan nilai balik.

Anda dapat membandingkan kesamaan dari sebuah konstanta enumerasi dengan sembarang objek lain, menggunakan equals(), yang mendefinisikan-ulang metode equals() yang didefinisikan oleh Object. Meskipun equals() dapat membandingkan sebuah konstanta enumerasi dengan sembarang objek lain, kedua objek tersebut dipandang sama jika keduanya mereferensi konstanta yang sama, di dalam enumerasi yang sama.

Program berikut mendemonstrasikan metode ordinal(), compareTo(), dan equals():

// Mendemonstrasikan metode ordinal(), compareTo(), dan equals().

// Sebuah enumerasi yang memuat nama-nama kota di Indonesia.
enum Kota {
   Malang, Medan, Jakarta, Jogja, Bandung
}

public class DemoEnum4 {
   public static void main(String args[])
   {
      Kota kt, kt2, kt3;
 
      // Mendapatkan semua nilai ordinal menggunakan ordinal().
      System.out.println("Berikut adalah semua konstanta kota" +
         " dan nilai ordinalnya: ");
 
      for(Kota a : Kota.values())
         System.out.println(a + " " + a.ordinal());
 
      kt = Kota.Jakarta;
      kt2 = Kota.Medan;
      kt3 = Kota.Jakarta;
 
      System.out.println();
 
      // Mendemonstrasikan compareTo() dan equals()
      if(kt.compareTo(kt2) < 0)
         System.out.println(kt + " ada sebelum " + kt2);
 
      if(kt.compareTo(kt2) > 0)
         System.out.println(kt2 + " ada sebelum " + kt);
 
      if(kt.compareTo(kt3) == 0)
         System.out.println(kt + " sama dengana " + kt3);
 
      System.out.println();
 
      if(kt.equals(kt2))
         System.out.println("Error!");
 
      if(kt.equals(kt3))
         System.out.println(kt + " sama dengan " + kt3);
 
      if(kt == kt3)
         System.out.println(kt + " == " + kt3);
 }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

Berikut adalah semua konstanta kota dan nilai ordinalnya: 
Malang 0
Medan 1
Jakarta 2
Jogja 3
Bandung 4

Medan ada sebelum Jakarta
Jakarta sama dengana Jakarta

Jakarta sama dengan Jakarta
Jakarta == Jakarta


Contoh Enumerasi Lain
Sebelum melanjutkan, Anda akan melihat satu lagi contoh enumerasi. Pada program ini, variabel dengan nama TIDAK, YA, MUNGKIN, NANTI, SEGERA, dan TIDAK_PERNAH akan dideklarasikan di dalam sebuah program dan dipakai untuk merepresentasikan jawaban-jawaban yang mungkin.

// Program ini menggunakan sebuah enumerasi untuk merepresentasikan
// jawaban-jawaban.

import java.util.Random;

// Sebuah enumerasi untuk kemungkinan jawaban.
enum Jawaban {
   TIDAK, YA, MUNGKIN, NANTI, SEGERA, TIDAK_PERNAH
}

class Pertanyaan {
   Random rand = new Random();

   Jawaban tanya() {
      int prob = (int) (100 * rand.nextDouble());

      if (prob < 15)
         return Jawaban.MUNGKIN; // 15%
      else if (prob < 30)
         return Jawaban.TIDAK; // 15%
      else if (prob < 60)
         return Jawaban.YA; // 30%
      else if (prob < 75)
         return Jawaban.NANTI; // 15%
      else if (prob < 98)
         return Jawaban.SEGERA; // 13%
      else
         return Jawaban.TIDAK_PERNAH; // 2%
   }
}

public class TanyaSaya {
   static void jawab(Jawaban hasil) {
      switch(hasil) {
         case TIDAK:
            System.out.println("Tidak");
            break;
   case YA:
            System.out.println("Ya");
            break;
         case MUNGKIN:
            System.out.println("Mungkin");
            break;
         case NANTI:
            System.out.println("Nanti");
            break;
         case SEGERA:
            System.out.println("Segera");
            break;
         case TIDAK_PERNAH:
            System.out.println("Tidak Pernah");
            break;
      }
   }
   
   public static void main(String args[]) {
   Pertanyaan q = new Pertanyaan();
   
   jawab(q.tanya());
   jawab(q.tanya());
   jawab(q.tanya());
   jawab(q.tanya());
   }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

Tidak Pernah
Ya
Nanti
Nanti


Pembungkus Tipe Data
Seperti Anda ketahui, Java menggunakan tipe data primitif (juga dikenal sebagai tipe data sederhana), seperti int atau double, untuk memuat tipe data dasar yang didukung oleh bahasa ini. Tipe data primitif, selain objek, dipakai untuk menampung nilai bulat dan pecahan agar program dapat berjalan sangat cepat. Tipe primitif tidak menjadi bagian dari hierarki objek dan tidak mewarisi Object.

Meskipun kinerja program sangat diuntungkan oleh tipe primitif, adakalanya ketika Anda memerlukan representasi objek. Misalnya, Anda tidak bisa melewatkan tipe data primitif dengan referensi kepada sebuah metode. Selain itu, banyak struktur data standar yang diimplementasikan oleh Java hanya bisa diterapkan pada objek, yang berarti bahwa Anda tidak bisa menggunakan struktur data tersebut untuk menyimpan tipe data primitif. Untuk menangani situasi semacam ini, Java menyediakan pembungkus tipe data, yang merupakan kelas-kelas yang mengenkapsulasi tipe data primitif ke dalam objek.

Tipe data pembungkus adalah Double, Float, Integer, Short, Byte, Character, dan Boolean. Setiap kelas ini dapat Anda pakai untuk mengintegrasikan tipe data primitif ekivalen ke dalam hierarki objek dalam Java.


Character
Character adalah pembungkus tipe data char. Konstruktor untuk Character adalah:

Character(char ch)

Di sini, ch menetapkan karakter yang akan dibungkus oleh objek Character yang sedang diciptakan.

Untuk mendapatkan nilai char yang dimuat di dalam sebuah objek Character, Anda memanggil charValue(), seperti ditunjukkan di sini:

Char charValue()

Metode ini menghasilkan karakter yang dienkapsulasi atau yang dibungkus di dalam sebuah objek Character.


Boolean
Boolean adalah sebuah kelas pembungkus untuk nilai boolean. Kelas ini mendefinisikan dua konstruktor berikut:

Boolean(boolean nilaiBool)
Boolean(String stringBool)

Pada versi pertamanya, nilaiBool harus bernilai true atau false. Pada versi keduanya, jika stringBool memuat string “true” (baik huruf besar maupun huruf kecil), maka objek Boolean yang baru akan bernilai true. Sebaliknya, akan bernilai false.


Pembungkus Tipe Data Numerik
Sejauh ini, pembungkus tipe data yang umum digunakan adalah yang merepresentasikan nilai-nilai numerik, yaitu Byte, Short, Integer, Long, Flat, dan Double. Semua pembungkus tipe data ini mewarisi kelas abstrak Number. Kelas Number mendeklarasikan metode-metode yang menghasilkan nilai dari sebuah objek pada tiap format bilangan yang berbeda. Metode-metode tersebut adalah:

byte byteValue()
double doubleValue()
float floatValue()
int intValue()
long longValue()
short shortValue()

Misalnya, metode doubleValue() menghasilkan nilai dari sebuah objek sebagai double, floatValue() menghasilkan nilai sebagai float, dan seterusnya.

Semua pembungkus tipe data numerik mendefinisikan konstruktor-konstruktor yang bisa dipakai untuk menciptakan objek dari nilai tertentu atau representasi string tertentu. Sebagai contoh, berikut adalah dua konstruktor yang didefinisikan untuk Integer:

Integer(int nil)
Integer(String str)

Jika str memuat sebuah nilai numerik yang valid, maka eksepsi NumberFormatException akan dilemparkan.

Semua pembungkus tipe mendefinisikan ulang metode toString(). Hal ini bisa Anda gunakan untuk menampilkan nilai dengan melewatkan objek pembungkus tipe kepada println(), misalnya, tanpa perlu mengkonversinya menjadi tipe data primitif.

Program berikut mendemonstrasikan bagaimana menggunakan sebuah pembungkus tipe data untuk mengenkapsulasi sebuah nilai dan kemudian mengekstraksi nilai tersebut:

// Mendemonstrasikan pembungkus tipe data
public class PembungkusTipeData {
   public static void main(String args[]) {
      Integer iOb = new Integer(100);
  
      int i = iOb.intValue();
  
      System.out.println(i + " " + iOb); // menampilkan 100 100
   }
}

Program ini membungkus nilai integer 100 di dalam sebuah objek Integer yang dinamakan dengan iOb. Program kemudian memperoleh nilai ini dengan memanggil intValue() dan menyimpan hasilnya ke dalam i.

Proses enkapsulasi sebuah nilai di dalam sebuah objek dinamakan dengan boxing atau pengotakan. Jadi, di dalam program, baris ini mengotakkan atau membungkus nilai 100 ke dalam sebuah objek Integer:

Integer iOb = new Integer(100);

Proses ekstraksi sebuah nilai dari pembungkus tipe dinamakan dengan unboxing, atau pembongkaran. Sebagai contoh, program mengekstraksi nilai di dalam iOb dengan statemen ini:

int i = iOb.intValue();

Prosedur yang sama dipakai oleh program untuk membungkus dan mengekstraksi nilai yang telah digunakan sejak awal lahirnya Java. Namun, sejak JDK 5, Java secara mendasar telah memperbaiknya dengan menambahkan autoboxing atau pembongkaran atau pengekstraksian nilai primitif di dalam sebuah objek.


Autoboxing
Mulai sejak JDK 5, Java telah menambahkan dua fitur penting: autoboxing dan auto-unboxing. Autoboxing adalah proses dimana sebuah tipe data primitif secara otomatis dienkapsulasi (dibungkus) ke dalam tipe data pembungkus (wrapper) ekivalen kapanpun objek dari tipe itu diperlukan. Tidak diperlukan menciptakan objek secara eksplisit. Auto-unboxing adalah proses dimana nilai dari sebuah objek enkapsulasi secara otomatis diekstraksi dari pembungkus tipe data kapanpun nilai primitifnya diperlukan. Tidak diperlukan pemanggilan metode semacam intValue() atau doubleValue().

Penambahan fitur autoboxing dan auto-unboxing memperkuat kode untuk sejumlah algoritma, yang mengeliminasi pekerjaan boxing dan unboxing secara manual. Kedua fitur ini juga membantu dalam menghindarkan kode dari error. Selain itu, kedua fitur ini sangat penting dalam pemrograman generik, yang hanya dapat diterapkan pada objek.

Dengan autoboxing, Anda tidak lagi perlu mengkonstruksi sebuah objek secara manual untuk membungkus sebuah tipe data primitif. Anda hanya perlu menugaskan nilai itu kepada referensi pembungkus-tipe data. Java secara otomatis akan menciptakan objek untuk Anda. Sebagai contoh, berikut adalah cara mutakhir untuk menciptakan sebuah objek Integer yang memiliki nilai 100:

Integer iOb = 100;  // mengenkapsulasi sebuah int

Perhatikan bahwa objek tidak secara eksplisit diciptakan melalui penggunaan new. Java menanganinya untuk Anda secara otomatis.

Untuk mengekstraksi nilai primitif dari sebuah objek, Anda hanya perlu menugaskan referensi objek tersebut kepada variabel bertipe primitif. Sebagai contoh, untuk meng-unbox iOb, Anda menggunakan ini:

int i = iOb;  // auto-box

Java menanganinya bagi Anda.

Berikut adalah sebuah program sebelumnya yang ditulis ulang untuk menerapkan autoboxing/unboxing:

// Demonstrate autoboxing/unboxing.
public class AutoBox {
   public static void main(String args[]) {
      Integer iOb = 100; // autobox sebuah int
  
      int i = iOb; // auto-unbox
  
      System.out.println(i + " " + iOb); // menampilkan 100 100
   }
}


Autoboxing dan Metode
Selain kasus penugasan sederhana, autoboxing secara otomatis terjadi ketika sebuah tipe data primitif harus dikonversi menjadi sebuah objek; auto-unboxing terjadi ketika sebuah objek harus dikonversi menjadi tipe data primitif. Jadi, autoboxing/unboxing bisa terjadi ketika argumen dilewatkan kepada sebuah metode, atau ketika sebuah nilai dihasilkan atau menjadi nilai balik oleh metode. Sebagai contoh, perhatikan berikut:

// Autoboxing/unboxing terjadi pada
// parameter metode dan nilai baliknya.

public class AutoBox2 {
   // Mengambil sebuah parameter Integer dan menghasilkan
   // nilai balik int;
   static int m(Integer v) {
      return v ; // auto-unbox menjadi int
   }
 
   public static void main(String args[]) {
      // Melewatkan sebuah int kepada m() dan menugaskan
      // nilai baliknya kepada sebuah Integer. Di sini,
      // argumen 100 diautobox menjadi Integer. Nilai
      // baliknya juga diautobox menjadi Integer.
      Integer iOb = m(100);
 
      System.out.println(iOb);
   }
}

Program ini menghasilkan keluaran berikut:

100

Pada program, perhatikan bahwa m() memiliki sebuah parameter Integer dan menghasilkan nilai balik sebuah int. Di dalam main(), m() diberikan nilai 100. Karena m() mengharapkan sebuah Integer, nilai ini akan dikonversi secara otomatis menjadi Integer. Kemudian, m() menghasilkan int ekivalen dari argumennya. Ini menyebabkan v diauto-unbox. Selanjutnya, nilai int ditugaskan kepada iOb pada main(), yang menyebabkan nilai balik int diautobox menjadi sebuah Integer.


Autoboxing/Unboxing Terjadi Pada Ekspresi
Umumnya, autoboxing dan unboxing terjadi kapanpun konversi ke objek atau konversi dari objek diperlukan. Ini berlaku pada ekspresi. Di dalam sebuah ekspresi, sebuah objek numerik secara otomatis diunbox (diekstraksi menjadi tipe data primitif). Keluaran ekspresi dikonversi ulang menjadi tipe data objek (rebox), jika diperlukan. Sebagai contoh, perhatikan program berikut:

// Autoboxing/unboxing terjadi di dalam ekspresi.

public class AutoBox3 {
   public static void main(String args[]) {
      Integer iOb, iOb2;
  
      int i;
      iOb = 100;
 
      System.out.println("Nilai semula dari iOb: " + iOb);
  
      // Berikut secara otomatis mengunbox 
      // (konversi menjadi tipe data primitif) iOb,
      // melakukan inkremen, dan kemudian mereboxes 
      // (konversi menjadi tipe data objek) hasilnya
      // kembali menjadi iOb (Integer).
      ++iOb;
      
      // Menampilkan tipe data dari iOb
      System.out.println("Tipe data dari iOb adalah " +
        iOb.getClass().getName());

  
      System.out.println("Setelah ++iOb: " + iOb);
  
      // Di sini, iOb diunbox, ekspresi kemudian dievaluasi,
      // dan hasilnya direbox dan ditugaskan kepada iOb2.
      iOb2 = iOb + (iOb / 3);
      System.out.println("iOb2 setelah ekspresi: " + iOb2);

      
      // Menampilkan tipe data dari iOb2
      System.out.println("Tipe data dari iOb2 adalah " +
        iOb2.getClass().getName());
      
      // Ekspresi sama dievaluasi, tetapi hasilnya
      // tidak direbox.
      i = iOb + (iOb / 3);
      System.out.println("i setelah ekspresi: " + i);  
   }
}

Ketika dijalankan, program ini menghasilkan keluaran berikut:

Nilai semula dari iOb: 100
Tipe data dari iOb adalah java.lang.Integer
Setelah ++iOb: 101
iOb2 setelah ekspresi: 134
Tipe data dari iOb2 adalah java.lang.Integer
i setelah ekspresi: 134

Pada program, perhatikan khusus pada baris ini:

++iOb;

Ini menyebabkan nilai di dalam iOb diinkremen. Cara kerjanya seperti ini: iOb diekstraksi (dikonversi menjadi tipe data primitif ekivalen, dalam hal ini int), nilainya diinkremen, dan hasilnya direbox (dikonversi ulang menjadi Integer).




No comments: