Thursday, September 7, 2017

Kuliah I Java: Variabel dan Perhitungan Bagian-2


2. Variabel dan Perhitungan


Menyimpan Karakter
Variabel bertipe char dapat menyimpan satu kode karakter. Variabel tipe ini menempati 16 bit atau 2 byte memori karena semua karakter dalam Java disimpan sebagai kode Unicode. Untuk mendeklarasikan dan menginisialisasi sebuah variabel karakter karakterKu, Anda dapat menggunakan statemen:

char karakterKu = ‘X’;

Ini menginisialisasi variabel dengan representasi karakter Unicode dari huruf ‘X’. Anda perlu selalu menempatkan kutip tunggal sebagai pembatas untuk literal karakter pada sebuah statemen seperti contoh ini, ‘X’. Ini diperlukan agar kompilator dapat membedakan antara karakter ‘X’ dari variabel dengan nama X. Perhatikan bahwa Anda tidak bisa menggunakan kutip ganda sebagai pembatas karakter karena kutip ganda dipakai untuk pembatas string karakter. Sebuah string karakter seperti “X” berbeda dari literal bertipe char ‘X’.


Runtun Escape Karakter
Umumnya, karakter-karakter yang dapat Anda ketikkan dari papantik atau keyboard merupakan fungsi kunci yang disediakan dan himpunan kode karakter yang diperlukan oleh fungsi tersebut sesuai dengan kebutuhan sistem Anda. Agar Anda bisa memasukkan sembarang karakter Unicode sebagai bagian dari kode sumber program, Anda dapat mendefinisikan karakter-karakter Unicode dengan menetapkan representasi heksadesimal dari kode-kode karakter pada sebuah runtun escape. Runtun escape adalah sebuah cara alternatif dalam menetapkan sebuah karakter yang didefinisikan dengan kode. Sebuah simbol backslash, \, mengindikasikan awal dari runtun escape.

Anda menciptakan sebuah runtun escape untuk karakter Unicode dengan mengawali empat dijit heksadesimal dari kode karakter dengan simbol \u. Karena pengkodean Unicode untuk huruf X adalah nilai heksadesimal 0x0058, maka Anda dapat mendeklarasikan dan mendefinisikan karakterKu dengan statemen berikut:

char karakterKu = ‘\u0058’;

Anda menempatkan runtun escape di antara dua tanda-kutip tunggal untuk mendefinisikan literal karakter. Hasilnya sama seperti statemen sebelumnya dimana Anda menggunakan ‘X’ sebagai nilai awal untuk karakterKu. Anda bisa memberikan sembarang karakter Unicode dengan cara ini, tentu saja sepanjang Anda mengetahui kodenya.

Karena simbol backslash mengindikasikan awal dari sebuah runtun escape, maka Anda harus selalu menggunakan runtun escape \\ untuk menetapkan sebuah karakter backslash sebagai literal karakter atau sebagai string teks.

Seperti yang telah Anda ketahui, Anda menuliskan string karakter dengan mengapitnya di antara dua tanda-kutip ganda, dan Anda menuliskan literal karakter dengan mengapitnya di antara dua tanda-kutip tunggal. Karena alasan ini, Anda juga memerlukan runtun escape \’ dan \” untuk menetapkan kedua karakter ini (tanda-kutip tunggal dan tanda-kutip ganda). Misalnya, untuk menampilkan keluaran:

“Hari Jum’at, kami akan pergi ke pantai”, ia berkata dengan riang.

Anda bisa menuliskan:

System.out.println(“\”Hari Jum\’at, kami akan pergi ke pantai\”, ia berkata dengan riang.”);

Ada sejumlah runtun escape lain yang Anda bisa gunakan untuk mendefinisikan karakter-karakter kontrol:

\b
Backspace
\g
Form feed
\n
New line
\r
Carriage return
\t
Tab


Aritmatika Karakter
Anda dapat melakukan aritmatika terhadap variabel char. Dengan karakterKu memuat karakter ‘X’, statemen:

karakterKu += 1;     // Menginkremen ke karakter berikutnya

akan menyebabkan nilai dari karakterKu diubah menjadi ‘Y’. Ini karena kode Unicode untuk ‘Y’ bernilai satu lebih tinggi daripada kode untuk ‘X’. Anda dapat menggunakan operator inkremen ++ untuk menambah kode yang tersimpan pada karakterKu dengan menuliskan:

++karakterKu;        // Menginkremen ke karakter berikutnya

Ketika Anda menggunakan variabel bertipe char pada sebuah ekspresi aritmatik, nilainya akan dikonversi menjadi tipe int sebelum perhitungan dilakukan. Anda bisa menuliskan statemen-statemen yang melibatkan nilai-nilai bertipe char berikut:

char aKar = 0;
char bKar = ‘\u0028’;
aKar = (char)(2*bKar + 8);

Statemen-statemen di atas menyebabkan variabel aKar memuat kode untuk huruf X, yaitu 0x0058.

Latihan
Aritmatika dengan Kode-Kode Karakter
Contoh ini akan mendemonstrasikan operasi-operasi aritmatik yang melibatkan nilai-nilai bertipe char:

public class PerhitunganKodeKarakter {
      public static void main(String[] args){
         char huruf1 = 'A';              // huruf1 adalah 'A'
         char huruf2 = (char)(huruf1+1); // huruf2 adalah 'B'
         char huruf3 = huruf2;    // huruf3 juga 'B'

         System.out.println("Berikut adalah sebuah runtun huruf: "+ huruf1 +
              huruf2 + (++huruf3));

         // huruf3 sekarang adalah 'C'
         System.out.println("Berikut adalah kode desimal untuk tiap huruf tersebut:\n"+
            huruf1 + ": " + (int)huruf1 +
            " " + huruf2 + ": " + (int)huruf2 +
            " " + huruf3 + ": " + (int)huruf3);
      }
}

Contoh ini akan menghasilkan keluaran:

Berikut adalah sebuah runtun huruf: ABC
Berikut adalah kode desimal untuk tiap huruf tersebut:
A: 65 B: 66 C: 67

Penjelasan
Tiga statemen pertama pada main() mendefinisikan tiga variabel bertipe char:

char huruf1 = 'A';         // huruf1 adalah 'A'
char huruf2 = (char)(huruf1+1); // huruf2 adalah 'B'
char huruf3 = huruf2;      // huruf3 juga 'B'

Konversi tipe eksplisit menjadi char dari nilai awal untuk huruf2 merupakan hal penting. Tanpa itu, kode program tidak akan bisa dikompilasi. Ekspresi huruf1 + 1 menghasilkan nilai bertipe int, dan kompilator tidak akan melakukan konversi tipe implisit secara otomatis menjadi char karena potensi hilangnya informasi.

Statemen selanjutnya menampilkan ketiga karakter:

         System.out.println("Berikut adalah sebuah runtun huruf: "+ huruf1 +
              huruf2 + (++huruf3));

Dua karakter pertama yang ditampilkan adalah yang disimpan pada huruf1 dan huruf2. Karakter ketiga adalah nilai yang disimpan pada huruf3 setelah variabel tersebut diinkremen sebesar 1.

Secara default, metode println() memperlakukan variabel bertipe char sebagai karakter yang akan ditampilkan. Anda tetap bisa menampilkan nilai yang disimpan pada sebuah variabel char sebagai nilai numeris dengan melakukan konversi tipe eksplisit menjadi int. Statemen selanjutnya mendemonstrasikan ini:

         System.out.println("Berikut adalah kode desimal untuk tiap huruf tersebut:\n"+
            huruf1 + ": " + (int)huruf1 +
            " " + huruf2 + ": " + (int)huruf2 +
            " " + huruf3 + ": " + (int)huruf3);

Statemen ini menampilkan nilai dari ketiga variabel sebagai karakter yang diikuti dengan nilai desimalnya.

Tentu, Anda bisa jadi ingin melihat kode karakter sebagai nilai heksadesimal. Anda dapat menampilkan sembarang nilai bertipe int sebagai string heksadesimal menggunakan metode toHexString dari kelas Integer pada pustaka standar. Tambahkan statemen keluaran berikut di akhir metode main():

System.out.println("Berikut adalah kode heksadesimal untuk tiap huruf:\n"+
      huruf1 + ": " + Integer.toHexString(huruf1) +
      " " + huruf2 + ": " + Integer.toHexString(huruf2) +
      " " + huruf3 + ": " + Integer.toHexString(huruf3));
}

Statemen ini akan menampilkan kode-kode karakter sebagai nilai-nilai heksadesimal:

Berikut adalah kode heksadesimal untuk tiap huruf:
A: 41 B: 42 C: 43

Metode toHexString() menghasilkan representasi string dari argumennya. Di sini, Anda memiliki nama dari sebuah variabel bertipe char sebagai argumen untuk ketiga pemanggilan metode ini. Anda bisa juga menempatkan sembarang ekspresi yang menghasilkan nilai bertipe int sebagai argumen dari metode toHexString(). Karena metode ini mensyaratkan argumen dengan tipe int, maka kompilator akan melakukan konversi tipe implisit secara otomatis menjadi tipe int untuk tiap argumen huruf1, huruf2, dan huruf3.


Operasi-Operasi Bitwise
Seperti yang telah Anda ketahui, semua variabel integer yang telah didiskusikan direpresentasikan secara internal sebagai bilangan biner. Sebuah nilai bertipe int memuat 32 dijit biner atau 32 bit. Anda dapat memanipulasi bit-bit tersebut menggunakan operator-operator bitwise yang disediakan:

&
AND
|
OR
^
XOR
~
Komplemen


Gambar 2-5

Tiap operator ini diterapkan pada bit-bit pada operand-operandnya dengan cara berikut:
*   Operator AND bitwise, &, mengkombinasikan bit-bit pada kedua operandnya sehingga jika bit pertama (bit dari operand pertama) DAN bit kedua (bit dari operand kedua) maka hasilnya adalah bit 1. Selain kondisi itu, hasilnya adalah bit 0.
*    Operator OR bitwise, |, mengkombinasikan bit-bit pada kedua operandnya sehingga jika salah satu (bit dari operand pertama ATAU bit dari operand kedua) bernilai 1 maka hasilnya adalah bit 1. Selain kondisi itu, hasilnya adalah bit 0.
*    Operator XOR bitwise, ^, mengkombinasikan bit-bit pada kedua operandnya sehingga jika keduanya (bit dari operand pertama dan bit dari operand kedua) bernilai sama maka hasilnya adalah bit 0. Selain kondisi itu, hasilnya adalah bit 1.
*   Operator komplemen, ~, mengambil satu operand dengan menginversi (membalikkan) semua bit-bit dari operand tersebut, sehingga tiap bit 1 menjadi bit 0, dan tiap bit 0 menjadi bit 1.

Anda dapat melihat efek dari operator-operator ini pada contoh-contoh yang ditunjukkan pada Gambar 2-5. Gambar tersebut menunjukkan dijit-dijit biner yang mengkonstruksi operand-operand dan hasil operasi. Ketiga operasi biner diterapkan terhadap pasangan-pasangan bit pada operand-operandnya secara bergiliran. Operator komplemen hanya membalikkan keadaan dari tiap bit pada operandnya sehingga bit 1 menjadi bit 0 dan bit 0 menjadi bit 1.

Konversi dari biner ke heksadesimal adalah hal mudah. Setiap grup empat biner dari kanan dikelompokkan menjadi satu dijit heksadesimal. Sebagai contoh, nilai dari a pada ilustrasi sebelumnya adalah:

Biner
0110
0110
1100
1101
Nilai Desimal
6
6
12
13
Heksadesimal
6
6
C
D

Jadi, nilai dari variabel a pada heksadesimal adalah 0x66CD, dimana prefiks 0x mengindikasikan bahwa ini adalah sebuah nilai heksadesimal. Variabel b pada ilustrasi memiliki nilai heksadesimal 0x000F.


Menggunakan Operator AND dan OR
Anda bisa melihat operator & dari perspektif lain: ia memaksa sebuah bit menjadi 0 jika bit mask bernilai 0 dan membiarkan bit apa adanya jika bit mask adalah 1. Jadi, operator & memberikan Anda cara untuk menon-aktifkan bit-bit tertentu dalam sebuah word, dan membiarkan bit-bit lain apa adanya. Anda bisa menciptakan sebuah mask dengan bit-bit 0 pada posisi-posisi yang ingin Anda jadikan menjadi bit 0 dan bit-bit 1 di posisi-posisi lain. Sama halnya, operator | memaksa sebuah bit menjadi 1 ketika bit mask bernilai 1, dan membiarkan bit apa adanya ketika bit mask bernilai 0.

Operator & dan | merupakan operator-operator bitwise yang paling sering digunakan. Anda bisa menggunakan satu bit sebagai indikator keadaan yang menentukan apakah sesuatu perlu ditampilkan, ketika nilai bit 1, atau tidak ditampilkan, ketika nilai bit 0. Ambil contoh sederhana, untuk memilih bit ketiga dari kanan pada variabel int bernama indikator, Anda bisa menuliskan:

bitKetiga = indikator & 0x4;      // Memilih bit ketiga

Bit ketiga dari variabel bitKetiga akan bernilai sama dengan bit ketiga pada variabel indikator dan semua bit lain dari variabel bitKetiga akan bernilai 0.


Heksadesimal
Biner
indikator
0xFF07
1111
1111
0000
0111
Nilai mask
0x4
0000
0000
0000
0100
indikator & 0x4
0x4
0000
0000
0000
0100

Semua nilai ini memiliki 32 bit, karena bertipe int. Yang ditunjukkan di sini hanya 16 bit saja, hanya untuk menunjukkan pada Anda bagaimana hal ini dilakukan. Nilai mask menetapkan semua bit bernilai 0 pada hasil kecuali untuk bit ketiga. Di sini, hasil ekspresi adalah tak-nol karena bit ketiga pada indikator adalah bit 1.

Di sisi lain, jika variabel indikator yang memuat nilai 0xFF09, maka hasilnya akan berbeda:


Heksadesimal
Biner
indikator
0xFF09
1111
1111
0000
1001
Nilai mask
0x4
0000
0000
0000
0100
indikator & 0x4
0x0
0000
0000
0000
0000

Hasil ekspresi sekarang adalah nol karena bit ketiga dari indikator adalah bit 0.
Seperti yang telah dijelaskan, Anda dapat menggunakan operator | untuk mengaktifkan bit tertentu. Sebagai contoh, untuk mengaktifkan bit ketiga pada indikator, Anda dapat menuliskan:

indikator = indikator | 0x4;      // Mengaktifkan bit ketiga

Anda dapat melihat bagaimana ini dilakukan pada indikator:


Heksadesimal
Biner
indikator
0xFF09
1111
1111
0000
1001
Nilai mask
0x4
0000
0000
0000
0100
indikator | 0x4
0xFF0D
1111
1111
0000
1101

Seperti yang dapat Anda lihat, efeknya adalah mengaktifkan bit ketiga dari indikator. Semua bit lain dipertahankan apa adanya. Tentu, jika bit ketiga telah aktif sebelumnya, maka bit tersebut tetap aktif (bernilai 1).

Anda dapat pula menggunakan operator-operator bitwise dengan formasi op=. Pengaktifan bit ketiga pada variabel indikator umumnya dilakukan dengan:

indikator |= 0x4;

Statemen ini tampak lebih ringkas dan mudah dibaca.

Untuk Menon-aktifkan bit tertentu, Anda bisa menggunakan operator & kembali, dengan sebuah mask dengan bit 0 untuk bit yang ingin Anda non-aktifkan, dan dengan bit 1 untuk bit-bit lain. Untuk menon-aktifkan bit ketiga dari variabel indikator, Anda bisa menuliskan:

indikator &= ~0x4;   // Menon-aktifkan bit ketiga

Operator ~ menegasikan atau membalikkan keadaan bit. Literal 0x4 adalah sebuah nilai dengan bit ketiga adalah bit 0 dan bit-bit lain adalah bit 1. Penerapan operator ~ pada literal tersebut akan membalikkan keadaan dari tiap bit, sehingga bit-bit 0 menjadi 1 dan bit 1 menjadi bit 0. Dengan variabel indikator memiliki nilai 0xFF07, maka hal ini dapat dijelaskan menjadi:


Heksadesimal
Biner
indikator
0xFF09
1111
1111
0000
1001
Nilai mask
0x4
0000
0000
0000
0100
~0x4
0xFFFB
1111
1111
1111
1011
indikator &~0x4
0xFF03
1111
1111
0000
0011

Anda akan melihat operator-operator bitwise ini dalam program contoh berikut.

Latihan
Operasi-Operasi AND dan OR Bitwise
Contoh ini adalah sejumlah contoh operasi yang telah Anda lihat sebelumnya:

import static java.lang.Integer.toBinaryString;

public class OperasiBitwise {
   
   public static void main(String[] args) {
      int indikator = 0xFF07;
      int pilihBit3 = 0x4; // Mask untuk memilih bit ketiga

      // Malakukan AND bitwise untuk memilih bit ketiga pada indikator
      System.out.println("indikator = " +
         toBinaryString(indikator));
      System.out.println("pilihBit3 = " +
         toBinaryString(pilihBit3));
      indikator &= pilihBit3;
      System.out.println("indikator & pilihBit3 = " +
      toBinaryString(indikator));

      // Melakukan OR bitwise untuk mengatifkan bit ketiga
      indikator = 0xFF09;
      System.out.println("\nindikator = "+
         toBinaryString(indikator));
      System.out.println("pilihBit3 = "+
         toBinaryString(pilihBit3));
      indikator |= pilihBit3;
      System.out.println("indikator | pilihBit3 = " +
         toBinaryString(indikator));

      // Sekarang menon-aktifkan kembali bit ketiga
      indikator &= ~pilihBit3;
      System.out.println("\nBit ketiga pada nilai sebelumnya dari indikator" +
         " telah dinon-aktifkan");
      System.out.println("indikator & ~pilihBit3 = " +
         toBinaryString(indikator));
   }
}

Contoh ini menghasilkan keluaran berikut:

indikator = 1111111100000111
pilihBit3 = 100
indikator & pilihBit3 = 100

indikator = 1111111100001001
pilihBit3 = 100
indikator | pilihBit3 = 1111111100001101

Bit ketiga pada nilai sebelumnya dari indikator telah dinon-aktifkan
indikator & ~pilihBit3 = 1111111100001001

Penjelasan
Contoh ini menggunakan fragmen-fragmen kode yang telah dijelaskan sebelumnya sehingga Anda dapat melihat bagaimana hal itu dapat dipakai sesuai yang telah dijelaskan. Salah satu kapabilitas baru yang dikenalkan di sini adalah kegunaan dari metode toBinaryString() yang didefinisikan pada kelas Integer. Diberikan statemen impor statik di bagian atas kode sumber program sehingga Anda tidak perlu menyebutkan nama kelas Integer setiap kali menggunakan metode tersebut. Metode toBinaryString() menghasilkan sebuah string yang memuat representasi biner dari nilai bertipe int yang dilewatkan sebagai argumen kepada metode itu. Anda dapat melihat dari keluaran untuk nilai dari pilihBit3 bahwa string tidak mencantumkan nol-nol depan. Tentu, keluaran akan lebih baik dengan nol-nol depan ditampilkan, tetapi Anda perlu memahami lebih jauh tentang bagaimana menangani string untuk melakukannya.


Menggunakan Operator XOR (Exclusive OR)
Operator ^ memiliki kemampuan menukar dua nilai dengan cara yang menakjubkan. Dimisalkan bahwa Anda mengeksekusi tiga statemen berikut:

a ^= b;
b ^= a;
a ^= b;

Efek dari ketiga statemen ini adalah menukar nilai a dan b, tetapi Anda perlu mengingat bahwa hal ini hanya bisa dilakukan terhadap integer. Anda dalat mencobanya untuk sembarang nilai a dan b, misalnya 0xD00F dan 0xABAD. Statemen pertama mengubah a menjadi sebuah nilai baru:

a ^= b
Heksadesimal
Biner
a
0xD00F
1101
0000
0000
1111
b
0xABAD
1010
1011
1010
1101
a dari a^b
0x7BA2
0111
1011
1010
0010

Statemen selanjutnya, yang menghitung nilai baru dari b menggunakan nilai baru dari a:

b ^= a
Heksadesimal
Biner
a
0x7BA2
0111
1011
1010
0010
b
0xABAD
1010
1011
1010
1101
b dari b^a
0xD00F
1101
0000
0000
1111

Jadi, sekarang b memiliki sebuah nilai yang sama dengan nilai a semula. Sekarang langkah terakhir, yang menghitung sebuah nilai baru untuk a menggunakan nilai baru dari b:

a ^= b
Heksadesimal
Biner
a
0x7BA2
0111
1011
1010
0010
b
0xD00F
1101
0000
0000
1111
a dari a^b
0xABAD
1010
1011
1010
1101

Lihatlah bahwa nilai a sekarang adalah nilai semula dari b. Jadi, Anda bisa menukar dua nilai integer, tanpa memerlukan memori ekstra. Tetapi Anda tidak bisa melakukannya pada nilai-nilai titik-mengambang.

Satu hal yang perlu Anda ketahui: Kehati-hatian diperlukan saat menginisialisasi variabel bertipe byte dan bertipe short menggunakan nilai heksadesimal. Sebagai contoh, Anda bisa jadi tergoda untuk menginisialisasi sebuah variabel bertipe byte dengan nilai biner 1111 1111 menggunakan statemen berikut:

byte semuaBitSatu = 0xFF;  // Salah!!!

Pada dasarnya, hasil ini menyebabkan error kompilasi. Literal 0xFF adalah bertipe int, jadi nilai binernya adalah 0000 0000 0000 0000 0000 0000 1111 1111. Nilai biner ini adalah ekivalen dengan nilai desimal 128, yang berada di luar rentang tipe byte. Nilai byte yang Anda inginkan adalah 1111 1111, yang ekivalen dengan nilai desimal -1, jadi cara yang benar untuk menginisialisasi semuBitSatu adalah dengan menuliskan:

byte semuaBitSatu = 0xFFFFFFFF;   // Benar!!!

Sekarang, kompilator akan membuang bit-bit orde-tinggi untuk memberikan hasil yang Anda inginkan.


Operasi-Operasi Penggeseran
Mekanisme lain yang dapat Anda lakukan terhadap variabel-variabel integer pada level bit adalah penggeseran. Anda dapat menggeser bit-bit pada sebuah integer ke kiri atau ke kanan. Anda dapat memandang proses penggeseran dijit-dijit biner ke kanan atau ke kiri sebagai operasi pembagian atau pemangkatan berbasis 2. Penggeseran nilai biner dari desimal 3, 0011, ke kiri sejauh satu bit sama dengan mengalikannya dengan dua. Nilai itu akan menjadi 0110, yang bernilai desimal 6. Penggeseran nilai desimal 3 ke kanan sejauh satu bit akan membagi nilai tersebut dengan 2, yang menghasilkan biner 0001, atau desimal 1.


Gambar 2-6
Java memiliki tiga operator penggeseran:

<< 
Menggeser ke kiri, dengan mengisi nol-nol dari kanan.
>> 
Menggeser ke kanan, dengan mempropagasikan bit tanda dari kiri.
>>> 
Menggeser ke kanan, dengan mengisi nol-nol dari kiri.

Efek dari tiap operator penggeseran ditampilkan pada Gambar 2-6. Tentu, jika bit orde-tinggi pada operasi >> pada Gambar 2-6 adalah nol, maka tidak akan ada tiga nol pada ujung paling-kiri dari hasil.

Operasi-operasi penggeseran seringkali dipakai bersamaan dengan operator-operator bitwise lainnya yang telah didiskusikan sebelumnya. Pada banyak sistem operasi, sebuah nilai 32-bit kadangkala dipakai untuk menyimpan beberapa nilai. Misalnya, Anda dapat menyimpan dua koordinat 16-bit pada sebuah word 32-bit. Ini diilustrasikan pada Gambar 2-7.


Gambar 2-7


Gambar 2-7 menunjukkan bagaimana operasi-operasi penggeseran dapat dipakai untuk mengekstraksi 16 bit kiri atau kanan dari variabel nilai. Anda dapat melihat di sini mengapa Anda memiliki operasi penggeseran kiri ekstra yang mempropagasi bit paling-kiri. Ketika bit tanda tidak dipropagasikan, operasi penggeseran kanan tidak memiliki interpretasi numeris untuk nilai-nilai negatif karena bit tanda diperlakukan sama seperti bit lainnya, dan nol-nol disisipkan dari kanan. Ketika bit tanda dipropagasikan, efeknya pada nilai-nilai negatif sama seperti pada nilai-nilai positif.

Latihan
Menggunakan Operasi-Operasi Penggeseran
Contoh ini menggunakan operator-operator penggeseran bersama dengan operator-operator bitwise lain untuk memaketkan empat nilai bertipe char menjadi sebuah variabel bertipe long:

import static java.lang.Long.toHexString;

public class PaketKarakter {
   public static void main(String[] args) {
      char hurufA = 'A';
      char hurufB = 'B';
      char hurufC = 'C';
      char hurufD = 'D';
      long dipaket = 0L;

      dipaket = hurufD; // Menyimpan D
     
      // Menggeser dan menambah huruf berikutnya - C
      dipaket = (dipaket << 16) | hurufC;
      // Menggeser dan menambah huruf berikutnya - B
      dipaket = (dipaket << 16) | hurufB;
      // Menggeser dan menambah huruf berikutnya - A
      dipaket = (dipaket << 16) | hurufA;

      System.out.println("dipaket sekarang memuat 0x" + toHexString(dipaket));

      // Sekarang mengekstraksi huruf-huruf dan menampilkannya
      long mask = 0xFFFF; // 16 bit paling-kanan sebagai 1
      // Mengekstraksi huruf paling-kanan
      char huruf = (char)(dipaket & mask);
      System.out.println("Dari kanan ke kiri, huruf-huruf pada dipaket:");
      System.out.println(" " + huruf + " 0x" + toHexString(huruf));

      dipaket >>= 16; // Membuang huruf paling-kanan
      // Mengekstraksi huruf paling-kanan yang baru
      huruf = (char)(dipaket & mask);
      System.out.println(" " + huruf + " 0x" + toHexString(huruf));

      dipaket >>= 16; // Membuang huruf paling-kanan
      // Mengekstraksi huruf paling-kanan yang baru
      huruf = (char)(dipaket & mask);
      System.out.println(" " + huruf + " 0x" + toHexString(huruf));

      dipaket >>= 16; // Membuang huruf paling-kanan
      // Mengekstraksi huruf paling-kanan yang baru
      huruf = (char)(dipaket & mask);
      System.out.println(" " + huruf + " 0x" + toHexString(huruf));
   }
}

Keluaran dari program ini:

dipaket sekarang memuat 0x44004300420041
Dari kanan ke kiri, huruf-huruf pada dipaket:
 A 0x41
 B 0x42
 C 0x43
 D 0x44

Penjelasan
Empat statemen pertama pada main() mendefinisikan variabel-variabel yang diinisialisasi dengan huruf-huruf yang akan dipaketkan ke dalam variabel, dipaket, yang bertipe long dan didefinisikan pada statemen kelima pada main(). Proses pemaketan diawali dengan menyimpan karakter pertama pada dipaket:

dipaket = hurufD; // Menyimpan D

Ingat bahwa 16 bit paling-kanan pada dipaket sekarang memuat kode karakter D. Kode karakter huruf D ini akhirnya digeser ke 16 bit paling kiri pada dipaket. Statemen berikutnya menyisipkan huruf berikutnya, C, ke dalam dipaket:

dipaket = (dipaket << 16) | hurufC;

Huruf C ini disisipkan dengan lebih dahulu menggeser ke kiri isi dari variabel dipaket sejauh 16 bit, dan kemudian hasilnya di-OR-kan dengan hurufC. Pada titik ini, 32 bit paling-kiri dari dipaket adalah nol dan 32 bit paling-kanan memuat D yang diikuti dengan C.

Dua statemen berikutnya mengulangi proses yang sama untuk menyisipkan B dan A:

dipaket = (dipaket << 16) | hurufB;
dipaket = (dipaket << 16) | hurufA;

Sekarang variabel dipaket memuat kode dari keempat karakter dengan urutan D, C, B, dan A. Keluaran ditampilkan oleh statemen berikut:

System.out.println("Dari kanan ke kiri, huruf-huruf pada dipaket:");

Statemen ini menggunakan metode toHexString() yang didefinisikan pada kelas Long untuk menghasilkan sebuah string yang memuat representasi heksadesimal dari nilai dari dipaket. Karena Anda menempatkan statemen impor statik untuk nama metode ini, Anda tidak perlu menyertakan nama kelas. Anda dapat melihat dari keluaran bahwa variabel dipaket sekarang memuat empat kode karakter 0x44, 0x43, 0x42, dan 0x41, yang merupakan kode untuk huruf D sampai A.

Program kemudian mendemonstrasikan bagaimana Anda dapat menggunakan operator penggeseran dan operator AND untuk mengekstraksi empat nilai char dari dipaket. Langkah pertama adalah mendefinisikan sebuah mask untuk menyeleksi 16 bit paling-kanan pada sebuah nilai bertipe long:

long mask = 0xFFFF; // 16 bit paling-kanan sebagai 1

Statemen selanjutnya menggunakan mask tersebut untuk memilih kode karakter paling-kanan pada dipaket:

char huruf = (char)(dipaket & mask);

Konversi tipe eksplisit menjadi tipe char dari hasil dari operasi AND terhadap mask dengan dipaket diperlukan karena kompilator tidak akan melakukan konversi tipe implisit secara otomatis dari tipe long ke tipe char.

Dua statemen berikutnya menampilkan penjelasan diikuti dengan huruf pertama dan kodenya:

System.out.println("Dari kanan ke kiri, huruf-huruf pada dipaket:");
System.out.println(" " + huruf + " 0x" + toHexString(huruf));

Untuk mendapatkan karakter berikutnya, Anda membuang karakter yang baru saja diekstraksi dan melakukan operasi AND terhadap hasilnya dengan mask sekali lagi:

dipaket >>= 16; // Membuang huruf paling-kanan
huruf = (char)(dipaket & mask);

Hasil dari operasi penggeseran kanan disimpan kembali ke dalam dipaket, jadi operasi AND terhadap mask dengan dipaket akan mengekstraksi huruf berikutnya. Ekstraksi terhadap dua huruf selanjutnya diulangi dengan proses yang sama.


Metode-Metode untuk Operasi-Operasi Bitwise
Selain fasilitas dasar untuk operasi-operasi pada level bit, Anda juga memiliki sejumlah metode yang tersedia pada kelas-kelas pustaka Java. Metode-metode yang mengimplementasikan operasi-operasi bitwise didefinisikan pada kelas Integer dan Long pada paket java.lang. Metode-metode pada kelas Integer hanya berlaku untuk nilai-nilai bertipe int, dan metode-metode pada kelas Long hanya berlaku untuk nilai-nilai bertipe long. Kedua kelas mendefinisikan metode-metode berikut:

Metode
Penjelasan
bitCount(arg)
Menghasilkan jumlah bit 1 pada sebuah integer biner yang disuplai sebagai arg. Nilai baliknya bertipe int.
highestOneBit(arg)
Menghasilkan sebuah integer dengan 1 bit tunggal pada posisi yang berkaitan 1 bit paling-kiri dari arg. Nilai balik yang dihasilkan bertipe sama dengan arg.
lowestOneBit(arg)
Menghasilkan sebuah integer dengan 1 bit tunggal pada posisi yang berkaitan 1 bit paling-kanan dari arg. Nilai balik yang dihasilkan bertipe sama dengan arg.
numberOfLeadingZeros(arg)
Menghasilkan banyak bit 0 yang ada sebelum bit 1 paling-kiri pada arg. Nilai balik yang dihasilkan bertipe int. Jika arg adalah nol, maka metode ini menghasilkan banyak total bit pada arg, yaitu 32 bit untuk tipe int dan 64 bit untuk tipe long.
numberOfTrailingZeros(arg)
Menghasilkan banyak bit 0 yang ada setelah bit 1 paling-kanan pada arg. Nilai balik yang dihasilkan bertipe int. Jika arg adalah nol, maka metode ini menghasilkan banyak total bit pada arg, yaitu 32 bit untuk tipe int dan 64 bit untuk tipe long.
reverse(arg)
Menghasilkan nilai yang didapatkan dengan membalikkan urutan bit-bit pada arg. Nilai balik bertipe sama dengan arg.
rotateLeft(arg, jarak)
Menghasilkan nilai yang didapatkan dengan merotasi bit-bit pada arg ke kiri sejauh jarak posisi bit, dimana jarak adalah sebuah nilai bertipe int. Rotasi kiri berarti bahwa bit-bit yang digeser di sebelah kiri ditempatkan ke posisi-posisi bit sebelah kanan. Nilai balik yang dihasilkan bertipe sama dengan arg.
rotateRight(arg, jarak)
Menghasilkan nilai yang didapatkan dengan merotasi bit-bit pada arg ke kanan sejauh jarak posisi bit, dimana jarak adalah sebuah nilai bertipe int. Rotasi kanan berarti bahwa bit-bit yang digeser di sebelah kanan ditempatkan ke posisi-posisi bit sebelah kiri. Nilai balik yang dihasilkan bertipe sama dengan arg.

Ketika Anda ingin menerapkannya tersebut pada sebuah nilai yang bertipe int, Anda memanggil metode dari kelas Integer, dan ketika Anda ingin menerapkannya tersebut pada sebuah nilai yang bertipe long, Anda memanggil metode dari kelas Long.

Untuk menghitung berapa banyak bit 1 pada sebuah integer, jika Anda melakukannya sendiri, hal itu memerlukan usaha yang ekstra. Dengan metode bitCount(), Anda bisa memperoleh hasil hanya menggunakan satu statemen. Perhatikan contoh-contoh berikut.

Pertama, dimisalkan Anda mendefinisikan sebuah variabel integer sebagai berikut:

int data = 0x0F00;   // Data ini adalah: 0000 0000 0000 0000 0000 1111 0000 0000

Anda sekarang dapat menerapkan metode bitCount() pada variabel tersebut. Anda perlu menggunakan metode pada kelas Integer karena data bertipe int:

int banyakBit1 = Integer.bitCount(data); // Hasil adalah 4

Variabel banyakBit1 akan memiliki nilai 4 karena data memuat empat bit 1. Anda menggunakan metode pada kelas Integer karena data bertipe int. Jika Anda menerapkannya pada sebuah argumen bertipe long, Anda harus menggunakan metode dari kelas Long.

Berikut adalah definisi dari variabel integer lain, kali ini bertipe long:

long angka = 0xF00000000000000FL;

Pola bit pada angka memiliki byte pertama 1111 0000 dan byte terakhir sebagai 0000 1111; semua byte lain bernilai nol. Perhatikan simbol L di akhir literal sangat penting di sini. Tanpa simbol itu, Anda dipandang memberikan literal bertipe int, dan tipe int hanya memiliki 32 bit, dan kompilator akan mengeluarkan pesan error.

Anda dapat merotasi bit-bit pada angka ke kiri sejauh dua bit dengan statemen berikut:

long hasil = Long.rotateLeft(angka, 2);

Variabel hasil akan ditetapkan menjadi sebuah nilai dimana byte pertama adalah 0xC0, byte terakhir adalah 0x3F, dan semua bit lain adalah nol. Bit-bit pada angka digeser ke kiri sejauh 2 posisi bit, dan dua bit 1 yang digeser di kiri akan ditempatkan ke posisi kanan.


Latihan
Metode-Metode Untuk Operasi Bit
Anda akan melihat efek dari beberapa metode yang telah didiskusikan. Contoh ini juga menunjukkan bagaimana metode-metode pada kelas Integer dan Long digunakan.

import static java.lang.Long.*;

public class CobaMetodeBit {
   public static void main(String[] args) {
      long angka = 0xF00000000000000FL;
      System.out.println("Variabel angka:\n" + toBinaryString(angka));

      long hasil = rotateLeft(angka,2);
      System.out.println("Variabel angka dirotasi ke kiri 2 bit:\n" +
         toBinaryString(hasil));
     
      hasil = rotateRight(angka, 3);
      System.out.println("Variabel angka dirotasi ke kanan 3 bit:\n" +
          toBinaryString(hasil));
     
      hasil = reverse(hasil);
      System.out.println("Hasil sebelumnya dibalik:\n" + toBinaryString(hasil));
     
      System.out.println("Banyak bit 1 pada angka:\n" + bitCount(angka));
   }
}

Keluaran program:

Variabel angka:
1111000000000000000000000000000000000000000000000000000000001111
Variabel angka dirotasi ke kiri 2 bit:
1100000000000000000000000000000000000000000000000000000000111111
Variabel angka dirotasi ke kanan 3 bit:
1111111000000000000000000000000000000000000000000000000000000001
Hasil sebelumnya dibalik:
1000000000000000000000000000000000000000000000000000000001111111
Banyak bit 1 pada angka:
8


Variabel-Variabel dengan Sejumlah Nilai Integer Tertentu
Anda akan memerlukan variabel-variabel yang dapat memiliki nilai-nilai tertentu. Sebagai contoh, dimisalkan bahwa Anda ingin mendefinisikan sebuah variabel integer dengan nama Hari, yang akan menyimpan sebuah nilai integer yang merepresentasikan sebuah hari. Variabel tersebut idealnya dibatasi untuk tujuh nilai yang mungkin, satu untuk tiap hari dari Senin sampai Minggu. Inilah di mana enumerasi menjadi pilihan. Anda bisa mendefinisikan sebuah enumerasi untuk kasus ini dengan statemen deklarasi berikut:

enum Hari {Senin, Selasa, Rabu, Kamis, Jumat, Sabtu, Minggu}

Ini mendefinisikan sebuah tipe data baru, Hari, untuk variabel-variabel yang hanya dapat menyimpan satu atau lebih nilai yang diapit sepasang kurung kurawal. Nama Senin, Selasan, dan seterusnya sampai Minggu dinamakan dengan konstanta enumerasi, dan hanya dapat diakses melalu variabel Hari. Perhatikan tidak adanya tanda titik-koma di akhir definisi enumerasi Hari. Karena Anda sedang mendefinisikan sebuah tipe data di sini, maka titik-koma tidak diperlukan.

Dengan tipe data ini, Anda sekarang dapat mendefinisikan variabel hariSeminggu seperti ini:

Hari hariSeminggu = Hari.Selasa;

Statemen ini mendeklarasikan variabel hariSeminggi sebagai tipe data Hari, dan menginisialisasinya dengan nilai Selasa. Perhatikan bahwa konstanta enumerasi harus diawali dengan nama tipe enumerasi. Jika Anda tidak menyebutkannya, kompilator tidak akan mengenali konstanta tersebut.

Sebuah enumerasi dapat memuat sebanyak mungkin konstanta enumerasi yang Anda perlukan. Berikut adalah sebuah tipe enumerasi untuk setiap bulan dalam setahun:

enum Bulan {Januari, Februari, Maret, April, Mei, Juni, Juli,
            Agustus, September, Oktober, November, Desember}

Anda dapat juga mendefinisikan sebuah variabel dengan tipe data Bulan seperti ini:

Bulan sekarang = Bulan.September; // Menginisialisasi dengan September

Jika Anda nantinya ingin mengubah nilai yang disimpan pada variabel sekarang, Anda dapat mengubah nilainya menjadi konstanta enumerasi yang berbeda:

sekarang = Bulan.Oktober;

Variabel sekarang sekarang memuat konstanta enumerasi Oktober. Perhatikan contoh berikut.


Latihan
Menggunakan Enumerasi
Berikut adalah sebuah program yang mendefinisikan enumerasi Hari dan beberapa variabel bertipe data Hari:

public class CobaEnumerasi {
   // Mendefinisikan sebuah tipe enumerasi untuk semua hari dalam seminggu
   enum Hari {Senin, Selasa, Rabu, Kamis, Jumat, Sabtu, Minggu}

   public static void main(String[] args) {
      // Mendefinisikan tiga variabel bertipe Hari
      Hari kemarin = Hari.Kamis;
      Hari sekarang = Hari.Jumat;
      Hari besok = Hari.Sabtu;

      // Menampilkan nilai dari tiap variabel bertipe Hari
      System.out.println("Sekarang adalah " + sekarang);
      System.out.println("Besok adalah " + besok);
      System.out.println("Kemarin adalah " + kemarin);
   }
}

Keluaran program:

Sekarang adalah Jumat
Besok adalah Sabtu
Kemarin adalah Kamis

Penjelasan
Kode ini sendiri sebenarnya apa yang telah Anda lihat sebelumnya. Ini merupakan deklarasi atas tipe enumerasi Hari, yang diikuti dengan metode main() yang memuat definisi dari tiga variabel bertipe Hari. Anda kemudian memiliki statemen-statemen keluaran untuk ketiganya.

Keluaran program tampak menarik diamati. Yang ditampilkan bukanlah nilai numerik dari tipe Hari, tetapi namanya. Ini merupakan cara default dimana sebuah nilai bertipe enumerasi direpresentasikan sebagai sebuah string karena nama lebih penting daripada nilai pada tipe enumerasi.

Perhatikan bahwa karena statemen yang mendefinisikan Hari mendefinisikan sebuah tipe baru, Anda tidak bisa memosisikannya di dalam tubuh metode main(). Definisi untuk Hari dapat pula ditempatkan di dalam file sumber terpisah dengan nama Hari.java.


Variabel Boolean
Variabel bertipe boolean hanya dapat memilih salah satu dari dua nilai, true atau false. Nilai true dan false keduanya adalah literal boolean. Tipe data boolean berasal dari nama seorang matematikawan George Boolean, yang menemukan aljabar Boolean. Anda dapat mendefinisikan sebuah variabel bertipe boolean dinamakan keadaan menggunakan statemen berikut:

boolean keadaan = true;

Statemen ini juga menginisialisasi variabel keadaan dengan nilai true.

Anda dapat pula menetapkan nilai dari sebuah variabel boolean pada statemen penugasan. Misalnya, statemen:

keadaan = false;

menetapkan nilai dari variabel keadaan menjadi false.

Pada titik ini, Anda tidak melakukan banyak hal pada variabel boolean, selain menetapkan nilanya menjadi true atau false. Tetapi, pada bab selanjutnya, Anda akan melihat bahwa variabel boolean dapat menjadi berguna dalam konteks pembuatan keputusan dalam program.

Sejumlah operator mengkombinasikan nilai-nilai boolean, termasuk operator AND boolean, OR boolean, dan negasi boolan. Hal ini akan didiskusikan pada bab selanjutnya.


Keutamaan Operator
Keutamaan operator menentukan urutan eksekusi operator pada sebuah statemen. Ekspresi aritmatik sederhana seperti 3+4*5 menghasilkan nilai 23 karena operasi perkalian dieksekusi lebih dahulu daripada operasi penjumlahan. Setiap operator dalam Java memiliki aturan keutamaan operator, seperti diunjukkan pada tabel berikut. Operator-operator dengan keutamaan lebih tinggi dieksekusi lebih dahulu daripada operator-operator dengan keutamaan lebih rendah. Derajat keutamaan tertinggi adalah operator-operator pada baris atas pada tabel, dengan keutamaan lebih rendah pada baris-baris yang ada di bawahnya. Operator-operator yang ada pada baris yang sama memiliki keutamaan yang sama.

Grup Keutamaan Operator
Asosiatifitas
(), [], postfiks ++, postfiks --
kiri
Unary +, unary -, prefiks ++, prefiks --, ~, !
kanan
(tipe), new
kiri
*, /, %
kiri
+, -
kiri
<<, >>, >>>
kiri
<, <=, >, >=, instanceof
kiri
==, !=
kiri
&
kiri
^
kiri
|
kiri
&&
kiri
||
kiri
?:
kiri
=, +=, -=, *=, /=, %=, <<=, >>=, >>>=, &=, |=, ^=
kanan

Secara definisi, operator postfiks ++ mengubah nilai dari operandnya setelah operator-operator lain pada ekspresi dieksekusi lebih dahulu, meskipun keutamaan postfiks ++ merupakan yang tertinggi. Pada kasus ini, keutamaan menentukan kepada variabel apa operator postfiks ++ diterapkan; dengan kata lain, postifks ++ hanya berperan pada variabel yang ada sebelumnya. Karena alasan ini, ekspresi banyakJeruk+++banyakApel yang telah dilihat sebelumnya dievaluasi sebagai (banyakJeruk++) + banyakApel, bukan banyakJeruk + (++banyakApel).

Urutan eksekusi atas operator-operator dengan keutamaan sama pada sebuah statemen ditentukan dengan apa yang dinamakan dengan asosiatifitas. Operator-operator yang ada pada baris sama pada tabel di atas memiliki asosiatifitas kiri atau kanan. Operator dengan asosiatifitas kiri menempel ke operand kirinya. Operator dengan asosiatifitas kanan menempel ke operand kanannya. Sebagai contoh, jika Anda menuliskan statemen:

a = b + c + 10;

maka asosiatifitas kiri yang melekat pada operator + mengimplikasikan bahwa statemen ini dieksekusi dengan:

a = (b + c) + 10;

Di sisi lain, operator = dan op= memiliki asosiatifitas kanan, sehingga jika Anda memiliki variabel int dengan nama a, b, c, dan d yang diinisialisasi dengan 1, maka statemen:

a += b = c += d = 10;

menetapkan a menjadi 12, b dan c menjadi 11, dan d menjadi 10. Statemen ini ekivalen dengan:

a += (b = (c += (d = 10)));







2 comments:

I M Ari Nrartha said...

Luar biasa, kapan ke mataram?

Rismon Hasiholan Sianipar said...

Minggu depan bro...awal oktober...Bagaimana bro GUI MATLAB untuk pembelajaran dan perkuliahannya...sudah selesai?