Bab.1 Kelas
Abstrak dan Antarmuka
1.1
Introduksi
Anda
mungkin telah belajar membuat program-program sederhana untuk menciptakan dan
menampilkan komponen-komponen GUI. Sudahkah Anda menulis kode untuk merespon
aksi atau tindakan pengguna, seperti pengklikan suatu tombol? Seperti yang
ditampilkan pada Gambar 1.1, ketika suatu tombol diklik, pesan ditampilkan pada
konsol.
Gambar
1.1 Program merespon kejadian aksi pengklikan-tombol
Untuk
menulis kode seperti itu, Anda perlu mengetahui tentang antarmuka. Suatu
antarmuka digunakan untuk mendefinisikan watak umum kelas-kelas (khususnya yang
saling tidak berelasi). Sebelum mendiskusikan antarmuka, akan didiskusikan
topik yang sangat berkorelasi dengan antarmuka, kelas abstrak.
1.2
Kelas Abstrak
Pada Bab.11, dalam buku JAVA:
Teori dan Implementasi, ObjekGeometri
didefinisikan sebagai superkelas untuk Lingkaran
dan PersegiPanjang.ObjekGeometri memodelkan fitur-fitur
umum objek geometri. Kedua kelas Lingkaran
dan PersegiPanjang memuat metode dapatLuas() dan metode dapatKeliling() untuk menghitung luas
dan keliling suatu lingkaran.Karena Anda dapat menghitung luas dan keliling
semua objek geometri, maka lebih baik mendefinisikan dapatLuas() dan dapatKeliling()
dalam kelas ObjekGeometri. Namun,
kedua metode tersebut tidak bisa diimplementasikan di dalam kelas ObjekGeometri, karena implementasinya
bergantung pada tipe spesifik suatu objek geometri. Metode seperti itu dikenal
dengan metode abstrak dan ditandai
dengan penggunaan pemodifikasi abstract
pada header metode.Setelah Anda mendefinisikan kedua metode tersebut di dalam ObjekGeometri, maka ObjekGeometri menjadi kelas abstrak.
Kelas abstrak ditandai dengan penggunaan pemodifikasi abstract pada header kelas. Dalam notasi diagram UML, nama kelas
abstrak dan metode abstrak dibuat huruf miring, seperti ditampilkan pada Gambar
1.2. Kode1.1 menyajikan kode sumber untuk kelas ObjekGeometri.
Kode1.1 ObjekGeometri.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
|
public abstract class ObjekGeometri {
private String warna = "putih";
private boolean terisi;
private java.util.Date
tanggalDiciptakan;
/** Menciptakan suatu objek geometri default
*/
protected ObjekGeometri() {
tanggalDiciptakan = new
java.util.Date();
}
/** Menciptakan suatu objek geometri dengan
warna dan nilai terisi tertentu
protected ObjekGeometri(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;
}
/** Metode abstrak dapatLuas */
public abstract double dapatLuas();
/** Metode abstrak dapatKeliling */
public abstract double dapatKeliling();
}
|
Kelas abstrak sama dengan kelas
biasa, tetapi Anda tidak bisa menciptakan instans dari kelas abstrak
menggunakan operator new.Metode
abstrak didefinisikan tanpa implementasi. Implementasinya disediakan oleh
subkelas.Suatu kelas yang memuat metode abstrak harus didefinisikan abstrak.
Konstruktor dalam kelas abstrak
harus didefinisikan terproteksi, karena hanya digunakan oleh subkelasnya saja. Ketika
Anda menciptakan suatu instans dari suatu subkelas konkrit, konstruktor
superkelasnya dipanggil untuk menginisialisasi bidang data yang didefinisikan
di dalam superkelas.
Kelas abstrak ObjekGeometri mendefinisikan fitur-fitur umum (data dan metode)
untuk objek-objek geometri dan menyediakan konstruktor-konstruktor yang sesuai.
Karena Anda tidak mengetahui bagaimana menghitung luas dan keliling suatu objek
geometri, maka dapatLuas dan dapatKeliling didefinisikan sebagai metode-metode
abstrak. Kedua metode ini diimplementasikan di dalam sub-sub kelas.
Gambar1.2 Kelas ObjekGeometri memuat metode-metode abstrak
Kode1.2 Lingkaran.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 Lingkaran extends ObjekGeometri{
private
double radius;
public
Lingkaran() {
}
public
Lingkaran (double radius) {
this.radius
= radius;
}
public
Lingkaran(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);
}
}
|
Kode1.3 PersegiPanjang.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 PersegiPanjang extends ObjekGeometri {
private
double lebar;
private double tinggi;
public
PersegiPanjang() {
}
public
PersegiPanjang(double lebar, double tinggi) {
this.lebar
= lebar;
this.tinggi
= tinggi;
}
public
PersegiPanjang(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);
}
}
|
1.2.1
Apa Keuntungan Metode Abstrak?
Anda
mungkin bertanya-tanya apakah keuntungan yang didapatkan dari penggunaan dapatLuas dan dapatKeliling sebagai metode abstrak dalam kelas ObjekGeometri bila dibandingkan bila
hanya mendefinisikan kedua metode tersebut di dalam tiap subkelas. Contoh berikut
ini menunjukkan keuntungan pendefinisian kedua metode tersebut di dalam kelas ObjekGeometri.
Kode1.4
menciptakan dua objek geometri, suatu lingkaran dan suatu persegi-panjang,
memanggil metode luasSama untuk
memeriksa apakah keduanya memiliki luas yang sama dan memanggil metode tampilObjekGeometri untuk
menampilkannya.
Kode1.4 UjiObjekGeometri.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
|
public class UjiObjekGeometri {
/** Main method */
public static void main(String[]
args) {
// Menciptakan dua objek geometri
ObjekGeometri geoObjek1 = new Lingkaran(5);
ObjekGeometri geoObjek2 = new PersegiPanjang(5, 3);
System.out.println("Dua objek
memiliki luas sama? " +
luasSama(geoObjek1, geoObjek2));
// Menampilkan lingkaran
tampilObjekGeometri(geoObjek1);
// Menampilkan persegi-panjang
tampilObjekGeometri(geoObjek2);
}
/** Suatu metode untuk membandingkan luas
dua objek geometri */
public static boolean luasSama(ObjekGeometri geoObjek1,
ObjekGeometri
geoObjek2){
return geoObjek1.dapatLuas() ==
geoObjek2.dapatLuas();
}
/** Suatu metode untuk menampilkan suatu
objek geometri */
public static void tampilObjekGeometri(ObjekGeometri objek){
System.out.println();
System.out.println("Luas adalah
" + objek.dapatLuas());
System.out.println("Keliling adalah
" + objek.dapatKeliling());
}
}
|
Keluaran
Dua objek
memiliki luas sama? false
Luas adalah
78.53981633974483
Keliling
adalah 31.41592653589793
Luas adalah
15.0
Keliling
adalah 16.0
Metode dapatLuas dan dapatKeliling didefinisikan dalam kelas ObjekGeometri dioverride dalam kelas Lingkaran dan kelas PersegiPanjang.
Statemen 5-6
ObjekGeometri geoObjek1 = new Lingkaran(5);
ObjekGeometri geoObjek2 = new
PersegiPanjang(5, 3);
menciptakan
suatu lingkaran dan suatu persegi-panjang dan menugaskan keduanya kepada
variabel geoObjek1 dan geoObjek2.Kedua variabel tersebut
bertipe ObjekGeometri.
Ketika
memanggil luasSama(geoObjek1, geoObjek2)
(pada baris 9), metode dapatLuas
yang didefinisikan dalam kelas Lingkaran
digunakan untuk geoObjek1.dapatLuas(),
karena geoObjek1 adalah suatu
lingkaran dan metode dapatLuas yang
didefinisikan dalam kelas PersegiPanjang
digunakan untuk geoObjek2.dapatLuas(),
karena geoObjek2 adalah suatu
persegi-panjang.
Dengan
logika yang sama, ketika memanggil tampilObjekGeometri(geoObjek1)
(pada baris 12), metode dapatLuas
dan dapatKeliling yang didefinisikan
dalam kelas Lingkaran digunakan dan
ketika memanggil tampilObjekGeometri(geoObjek2)
(pada baris 15), metode dapatLuas
dan dapatKeliling yang didefinisikan
dalam kelas PersegiPanjang
digunakan.
1.2.2
Hal-Hal Penting Pada Kelas Abstrak
Berikut
adalah hal-hal penting seputar kelas abstrak:
·
Metode abstrak tidak dapat dimuat dalam suatu kelas
nonabstrak. Jika subkelas dari suatu superkelas abstrak tidak
mengimplementasikan semua metode abstrak, maka subkelas tersebut harus
didefinisikan abstrak. Dengan kata lain, di dalam suatu subkelas nonabstrak yang
mewarisi dari superkelas abstrak, semua metode abstrak harus diimplementasikan.
Perhatikan bahwa metode abstrak bersifat nonstatik.
·
Kelas abstrak tidak bisa diinstansiasi menggunakan
operator new, tetapi Anda masih bisa
mendefinisikan konstruktor-konstruktornya, yang dipanggil dari
konstruktor-konstruktor subkelas. Sebagai contoh, konstruktor ObjekGeometri dapat dipanggil dari
kelas Lingkaran dan dari kelas PersegiPanjang.
·
Suatu kelas yang memuat metode abstrak harus
didefinisikan abstrak. Akan tetapi, adalah hal mungkin untuk mendefinisikan
kelas abstrak yang tak memuat satupun metode abstrak. Pada kasus ini, Anda
tidak bisa menciptakan instans kelas menggunakan operator new. Kelas ini digunakan sebagai kelas basis untuk mendefinisikan
sub-subkelas baru.
·
Suatu kelas dapat menjadi abstrak bahkan jika
superkelasnya konkrit. Sebagai contoh, kelas Object adalah konkrit, tetapi
sub-subkelasnya dapat konrit, seperti ObjekGeometri.
·
Suatu subkelas dapat mengoverride suatu metode dari
superkelas yang mendefinisikannya sebagai abstrak. Hal ini sangat tidak biasa
tetapi penting ketika implementasi metode di dalam superkelas menjadi invalid
di dalam subkelas. Pada kasus ini, subkelas tersebut dapat didefinisikan
sebagai abstrak.
·
Anda tidak bisa menciptakan suatu instans dari kelas
abstrak menggunakan operator new,
tetapi suatu kelas abstrak dapat digunakan sebagai tipe data. Oleh karena itu,
statemen berikut ini, yang menciptakan suatu array yang memiliki elemen-elemen
bertipe ObjekGeometri, adalah benar:
ObjekGeometri[]
objek = new ObjekGeometri [10];
Anda
kemudian dapat menciptakan suatu instans ObjekGeometri dan menugaskan
referensinya kepada array seperti ini:
objek[0] = new Lingkaran();
1.3
Contoh: Calendar dan GregorianCalendar
Suatu
instans java.util.Date
merepresentasikan waktu spesifik dalam kepresisian milidetik. java.util.Calendar merupakan suatu
kelas basis untuk mengekstrak informasi kalender yang detil, seperti tahun,
bulan, tanggal, jam, menit, dan detik. Sub-subkelas dari Calendar dapat mengimplementasikan sistem-sistem kalender spesifik,
seperti kalender Gregorian, kalender Lunar, dan kalender Yahudi. Saat ini, java.util.GregorianCalendar untuk
kalender Gregorian telah didukung oleh JAVA, seperti ditampilkan pada Gambar
1.3. Metode add adalah metode abstrak dalam kelas Calendar, karena implementasinya tergantung pada sistem kalender
konkrit.
Gambar
1.3 Kelas Calendar abstrak mendefinisikan fitur-fitur umum berbagai sistem
kelender.
Anda
dapat menggunakan new
GregorianCalendar() untuk mengkonstruksi GregorianCalendar default dengan waktu sekarang dan new GregorianCalendar(year, month, date)
untuk mengkonstruksi GregorianCalendar
dengan tahun, bulan, dan tanggal tertentu.Parameter month dimulai dari 0,
dimana 0 adalah Januari.
Metode get(int field) didefinisikan di dalam
kelas Calendar berguna untuk
mengekstrak informasi tanggal dan waktu dari suatu objek Calendar. Beberapa field didefinisikan sebagai konstanta, seperti
tertampil pada Tabel 1.1.
Tabel
1.1 Konstanta-konstanta field di
dalam kelas Calendar
Konstanta
|
Deskripsi
|
YEAR
MONTH
DATE
HOUR
HOUR_OF_DAY
MINUTE
SECOND
DAY_OF_WEEK
DAY_OF_MONTH
DAY_OF_YEAR
WEEK_OF_MONTH
WEEK_OF_YEAR
AM_PM
|
Tahun
kalender.
Bulan
kalender dengan 0 untuk Januari.
Hari
kalender.
Jam
kelender (notasi 12-jam).
Jam
kelender (notasi 24-jam).
Menit
kalender.
Detik
Kalender.
Jumlah
hari dalam seminggu dengan 1 untuk Minggu.
Sama
dengan DATE.
Jumlah
hari dalam setahun dengan 1 untuk hari pertama.
Jumlah
minggu dalam sebulan dengan 1 untuk minggu pertama.
Jumlah
minggu dalam setahun dengan 1 untuk minggu pertama.
Indikator
untuk AM atau PM (0 untuk AM dan 1 untuk PM).
|
Kode1.5 UjiKalender.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
|
import java.util.*;
public class UjiKalender {
public static void main(String[]
args) {
// Menciptakan suatu kalender Gregorian
untuk tanggal dan waktu saat ini
Calendar kalender = new
GregorianCalendar();
System.out.println("Waktu sekarang
adalah " + new Date());
System.out.println("YEAR:\t" + kalender.get(Calendar.YEAR));
System.out.println("MONTH:\t" + kalender.get(Calendar.MONTH));
System.out.println("DATE:\t" + kalender.get(Calendar.DATE));
System.out.println("HOUR:\t" + kalender.get(Calendar.HOUR));
System.out.println("HOUR_OF_DAY:\t"
+
kalender.get(Calendar.HOUR_OF_DAY));
System.out.println("MINUTE:\t" +
kalender.get(Calendar.MINUTE));
System.out.println("SECOND:\t" +
kalender.get(Calendar.SECOND));
System.out.println("DAY_OF_WEEK:\t"
+
kalender.get(Calendar.DAY_OF_WEEK));
System.out.println("DAY_OF_MONTH:\t"
+
kalender.get(Calendar.DAY_OF_MONTH));
System.out.println("DAY_OF_YEAR:
" +
kalender.get(Calendar.DAY_OF_YEAR));
System.out.println("WEEK_OF_MONTH:
" +
kalender.get(Calendar.WEEK_OF_MONTH));
System.out.println("WEEK_OF_YEAR:
" +
kalender.get(Calendar.WEEK_OF_YEAR));
System.out.println("AM_PM: " + kalender.get(Calendar.AM_PM));
// Menciptakan kalender untuk 11 September
2001
Calendar kalender1= new GregorianCalendar(2001, 8, 11);
System.out.println("September 11,
2001 adalah hari " +
namaHariDalamMinggu(kalender1.get(Calendar.DAY_OF_WEEK)));
}
public static String namaHariDalamMinggu(int
hariDalamMinggu) {
switch (hariDalamMinggu) {
case 1: return "Minggu";
case 2: return "Senin";
case 3: return "Selasa";
case 4: return "Rabu";
case 5: return "Kamis";
case 6: return "Jumat";
case 7: return "Sabtu";
default: return null;
}
}
}
|
Keluaran
Waktu sekarang
adalah Wed Nov 21 16:47:18 ICT 2012
YEAR: 2012
MONTH: 10
DATE: 21
HOUR: 4
HOUR_OF_DAY: 16
MINUTE: 47
SECOND: 18
DAY_OF_WEEK: 4
DAY_OF_MONTH: 21
DAY_OF_YEAR:
326
WEEK_OF_MONTH:
4
WEEK_OF_YEAR:
47
AM_PM: 1
September 11,
2001 adalah hari Selasa
Metode set(int field, value) yang
didefinisikan di dalam kelas Calendar
dapat digunakan untuk menetapkan field.
Sebagai contoh, Anda dapat menggunakan kalender.set(Calendar.DAY_OF_MONTH,
1) untuk menetapkan kalender menjadi hari pertama dalam sebulan.
Metode add(field, value) menambahkan jumlah
waktu tertentu kepada field yang diberikan. Sebagai contoh, add(Calendar.DAY_OF_MONTH, 5) menambahkan
lima hari kepada waktu sekarang pada kalender dan add(Calendar.DAY_OF_MONTH, -5) mengurangkan lima hari dari waktu
sekarang pada kalender.
Untuk
mendapatkan jumlah hari dalam satu bulan, digunakan kalender.getActualMaximum(Calendar.DAY_OF_MONTH). Sebagai contoh,
jika kalender adalah Maret, maka
metode akan mengembalikan nilai 31.
Anda
bisa menetapkan suatu waktu di dalam objek Date
pada kalender dengan memanggil kalender.setTime(date)
dan mengekstrak waktu tersebut dengan memanggil kalender.getTime().
1.4
Antarmuka
Antarmuka
adalah konstruksi seperti kelas yang hanya memuat konstanta-konstanta dan
metode-metode abstrak. Dalam berbagai kasus, antarmuka sama dengan kelas
abstrak, tetapi tujuannya adalah untuk menentukan watak umum dari objek.
Sebagai contoh, dengan menggunakan antarmuka yang sesuai, Anda dapat menentukan
apakah antarmuka komparabel (comparable),
edibel (edible), atau klonabel (cloneable).
Untuk
membedakan antarmuka dari kelas, JAVA menggunakan sintaks berikut ini untuk
mendefinisikan suatu antarmuka:
pemodifikasi interface namaAntarMuka {
/** Deklarasi konstanta-konstanta */
/** Sidik-sidik metode */
}
Berikut
merupakan suatu contoh antarmuka:
public interface Edible {
/** Menjelaskan bagaimana
memakan */
public abstract String bagaimanaMemakan();
}
Antarmuka
diperlakukan seperti kelas dalam JAVA. Setiap antarmuka dikompilasi menjadi
file bytecode terpisah, sama seperti kelas biasa. Seperti kelas abstrak, Anda
tidak bisa menciptakan suatu instans dari antarmuka menggunakan operator new, tetapi pada banyak kasus Anda
dapat menggunakan antarmuka kurang lebih sama dengan ketika Anda menggunakan
kelas abstrak. Sebagai contoh, Anda dapat menggunakan antarmuka sebagai tipe
data untuk suatu variabel referensi, sebagai hasil casting, dan seterusnya.
Anda
sekarang dapat menggunakan antarmuka Edible
untuk menentukan apakah suatu objek dapat dimakan atau tidak. Ini dilakukan
dengan mengijinkan kelas agar objek mengimplementasikan antarmuka ini
menggunakan katakunci implements.
Sebagai contoh, kelas Ayam dan kelas
Buah pada kode1.6 (baris 14, 23)
mengimplementasikan antarmuka Edible.
Relasi antara kelas dan antarmuka dikenal dengan pewarisan antarmuka. Karena
pewarisan antarmuka dan pewarisan kelas secara esensi sama, maka keduanya
disebut dengan pewarisan saja.
Kode1.6 UjiEdible.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
|
public class UjiEdible {
public
static void main(String[] args) {
Object[] objek = {new Harimau(), new
Ayam(), new Apel()};
for (int i = 0; i <
objek.length; i++)
if (objek[i] instanceof
Edible)
System.out.println(((Edible)objek[i]).bagaimanaMemakan());
}
}
class Binatang {
//
Bidang data, konstruktor, dan metode diabaikan
}
class Ayam extends Binatang implements
Edible {
public
String bagaimanaMemakan() {
return "Ayam: Goreng
saja";
}
}
class Harimau extends Binatang {
}
abstract class Buah implements Edible {
// Bidang data, konstruktor, dan metode
diabaikan
}
class Apel extends Buah {
public String bagaimanaMemakan() {
return "Apel: Kupas dan
makan";
}
}
class Jeruk extends Buah {
public String bagaimanaMemakan() {
return "Jeruk: Dibuat
jus";
}
}
|
Keluaran
Ayam: Goreng
saja
Apel: Kupas
dan makan
Kelas Ayam mewarisi Binatang dan mengimplementasikan Edible untuk menentukan apakah ayam dapat dimakan atau tidak.
Ketika suatu kelas mengimplementasikan antarmuka, maka semua metode yang
didefinisikan di dalam antarmuka diimplementasikan dengan sidik dan tipe nilai
balik yang persis sama. Kelas Ayam
mengimplementasikan metode bagaimanaMemakan()
(baris 15-17).
Kelas Buah mengimplementasikan Edible. Karena kelas Buah tidak mengimplementasikan metode bagaimanaMemakan(), maka Buah harus didefinisikan abstract (baris 23). Sub-subkelas
konkrit dari Buah harus mengimplementasikan metode bagaimanaMemakan(). Kelas Apel
dan Jeruk mengimplementasikan metode
bagaimanaMemakan() (baris 28, 34).
1.5
Contoh: Antarmuka Comparable
Dimisalkan
Anda ingin mendesain suatu metode generik untuk mencari mana yang lebih besar
dari dua objek yang bertipe sama, seperti dua mahasiswa, dua tanggal, dua
lingkaran, atau dua persegi-panjang. Untuk melakukannya, dua objek harus
komparabel atau dapat dibandingkan. Jadi, watak umum objek adalah komparabel.
JAVA menyediakan antarmuka Comparable
untuk tujuan ini. Antarmuka ini didefinisikan sebagai berikut:
//
Antarmuka untuk membandingkan objek, didefinisikan di dalam java.lang
package java.lang;
public interface Comparable {
public int compareTo(Object o);
}
Metode compareTo menentukan urutan objek ini
dengan objek tertentu o dan
menghasilkan suatu integer negatif, nol, atau positif jika objek ini kurang
dari, sama dengan, atau lebih besar dari o.
Banyak
kelas dalam pustaka JAVA (misalnya, String
dan Date) mengimplementasikan
antarmuka Comparable untuk
menentukan urutan objek-objek. Jika Anda memeriksa kode-kode kelas ini, Anda
akan menemukan katakunci implements
digunakan, seperti ditunjukkan di bawah ini:
Jadi,
watak string adalah komparabel, dan begitu juga dengan tanggal.Dimisalkan s adalah suatu objek String dan d adalah suatu objek Date,
maka semua ekspresi berikut adalah true:
Suatu
metode generik, max, untuk mencari
yang lebih besar dari dua objek dapat didefinisikan seperti pada (a) atau (b)
di bawah ini:
Metode max pada (a) lebih sederhana dari (b).
Dalam kelas Max pada (b), o1
dideklarasikan sebagi Object, dan (Comparable).o1 memberitahukan kepada
kompiler untuk melakukan casting terhadap o1
menjadi Comparable sehingga metode compareTo dapat dipanggil dari o1.
Metode
max pada (a) lebih handal dari (b). Anda harus memanggil metode max dengan dua objek yang komparabel.
Seandainya Anda memanggil metode max dengan dua objek non-komparabel:
Max.max(sembarangObjek1,
sembarangObjek2);
Kompiler
akan mendeteksi error menggunakan metode max
pada (a), karena sembarangObjek1
bukan suatu instans dari Comparable.
Menggunakan metode max pada (b),
kode tersebut akan baik-baik saja, tetapi akan mengalami ClassCastException, karena sembarangObjek1
bukan suatu instans dari Comparable dan
tidak bisa dilakukan casting menjadi Comparable.
Mulai
dari sekarang, diasumsikan bahwa metode max
pada (a) yang digunakan. Karena string dan tanggal adalah komparabel, maka Anda
dapat menggunakan metode max untuk
mencari yang lebih besar dari dua instans String
dan Date. Berikut adalah salah satu
contohnya:
Nilai return pada metode max bertipe Comparable.
Jadi, Anda melakukan casting terhadap nilai return menjadi String
atau Date secara eksplisit.
Anda
tidak bisa menggunakan metode max
untuk mencari yang lebih besar dari dua instans PersegiPanjang, karena PersegiPanjang
tidak mengimplementasikan Comparable.
Instans-instans kelas baru ini adalah komparabel. Kelas baru ini diberi nama PersegiPanjangKomparabel, seperti
ditampilkan pada kode1.7:
Kode1.7 PersegiPanjangKomparabel.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
public class PersegiPanjangKomparabel extends
PersegiPanjang
implements Comparable{
/** Menciptakan suatu PersegiPanjangKomparabel
dengan properti tertentu */
public
PersegiPanjangKomparabel(double lebar, double tinggi) {
super(lebar, tinggi);
}
/** Mengimplementasikan metode compareTo didefinisikan
dalam Comparable */
public int compareTo(Object o){
if (dapatLuas() >
((PersegiPanjangKomparabel)o).dapatLuas())
return 1;
else if (dapatLuas() <
((PersegiPanjangKomparabel)o).dapatLuas())
return -1;
else
return 0;
}
}
|
PersegiPanjangKomparabel
mewarisi PersegiPanjang dan
mengimplementasikan Comparable,
seperti ditampilkan pada Gambar 1.4. Katakunci implements mengindikasikan bahwa PersegiPanjangKomparabel mewarisi semua konstanta dari antarmuka Comparabel dan mengimplementasikan
semua metodenya. Suatu instans PersegiPanjangKomparabel
juga merupakan instans dari PersegiPanjang,
ObjekGeometri, Object, dan Comparable.
Gambar
1.4 PersegiPanjangKomparabel mewarisi PersegiPanjang dan mengimplementasikan Comparable
Anda
sekarang dapat menggunakan max untuk
yang lebih besar dari dua objek PersegiPanjangKomparabel.
Berikut adalah salah satu contohnya:
PersegiPanjangKomparabel
persegipanjang1 = new PersegiPanjangKomparabel
(4, 5);
PersegiPanjangKomparabel
persegipanjang12= new PersegiPanjangKomparabel
(3, 6);
System.out.println(Max.max(persegipanjang1,
persegipanjang2));
Suatu
antarmuka menyediakan suatu bentuk lain dari pemrograman generik. Akan sangat
sulit bila menggunakan suatu metode generik max untuk mencari objek maksimum tanpa menggunakan antarmuka pada
contoh ini, karena pewarisan jamak perlu untuk mewarisi Comparable dan kelas lain, seperti PersegiPanjang, pada saat yang sama.
Kelas Object memiliki metode equals, yang ditujukan bagi sub-subkelas
Objects untuk mengoverride untuk
memeriksa apakah dua objek sama atau tidak. Dimisalkan kelas Object mempunyai metode compareTo, seperti didefinisikan pada
antarmuka Comparable, maka metode max dapat digunakan untuk membandingkan
suatu daftar yang berisi objek-objek. Apakah metode compareTo seharusnya disertakan dalam kelas Object itu masih bisa diperdebatkan. Karena metode compareTo tidak didefinisikan di dalam Object, maka antarmuka Comparable
didefinisikan di dalam JAVA agar objek-objek dapat dibandingkan jika
objek-objek merupakan instans dari antarmuka Comparable. Sangat direkomendasikan bahwa compareTo harus konsisten dengan equals. Yaitu, untuk dua objek o1
dan o2, o1.compareTo(o2) == 0 jika dan hanya jika o1.equals(o2) bernilai true.
1.6
Contoh: Antarmuka ActionListener
Sekarang
Anda telah siap untuk menulis suatu program singkat untuk menjawab tantangan
yang diberikan pada awal bab ini. Program menampilkan dua tombol di dalam
frame, seperti ditampilkan pada Gambar 1.1. Untuk merespon suatu pengklikan
tombol, Anda perlu menulis kode untuk memproses aksi pengklikan-tombol. Tombol
merupakan objek sumber atau source object
dimana aksi berasal. Anda perlu menciptakan suatu objek yang dapat menangani
aksi penekanan-tombol tersebut. Objek ini disebut dengan suatu listener,
seperti tertampil pada 1.5.
Tidak
semua objek dapat menjadi listener dari antarmuka ActionListener. Ada dua syarat agar objek bisa menjadi listener:
·
Objek harus merupakan instans dari antarmuka ActionListener. Antarmuka ini mendefinisikan
watak umum untuk semua aksi listener.
·
Objek ActionListener,
pendengar, harus terdaftar dengan
sumber menggunakan metode sumber.addActionListener(pendengar).
Gambar
1.5 Objek listener memproses event
atau kejadian yang dipicu dari objek sumber
Antarmuka
ActionListener memuat metode actionPerformed untuk memproses
event.Kelas listener Anda harus mengoverride metode ini untuk merespon
kejadian. Kode1.8 menyajikan suatu contoh kode yang memproses ActionEvent pada dua tombol. Ketika
Anda menekan tombol OK, pesan “Tombol OK diklik”ditampilkan. Ketika Anda
menekan tombol Batak, pesan “Tombol Batal diklik”ditampilkan, seperti
ditampilkan pada Gambar 1.1.
Kode1.8 PenangananEvent.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
|
import javax.swing.*;
import java.awt.event.*;
public class PenangananEvent
extends JFrame{
public PenangananEvent() {
// Menciptakan dua tombol
JButton jbtOK = new JButton("OK");
JButton jbtBatal = new
JButton("Batal");
// Menciptakan panel yang menampung tombol
JPanel panel = new JPanel();
panel.add(jbtOK);
panel.add(jbtBatal);
add(panel); // Menambahkan panel ke dalam
frame
// Mendaftarkan listener
OKListenerClass listener1 = new OKListenerClass();
CancelListenerClass listener2 = new
CancelListenerClass();
jbtOK.addActionListener(listener1);
jbtBatal.addActionListener(listener2);
}
public static void main(String[] args) {
JFrame frame = new PenangananEvent();
frame.setTitle("Penanganan Event");
frame.setSize(200, 150);
frame.setLocation(200, 100);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);
}
}
class OKListenerClass
implements ActionListener{
public
void actionPerformed(ActionEvent e) {
System.out.println("Tombol OK
diklik");
}
}
class CancelListenerClass
implements ActionListener{
public void actionPerformed(ActionEvent e) {
System.out.println("Tombol Batal
diklik");
}
}
|
Dua
kelas listener didefinisikan pada baris 34-44. Setiap kelas listener
mengimplementasikan ActionListener
untuk memproses ActionEvent. Objek listener1 merupakan instans dari OKListenerClass (baris 18), yang
didaftarkan dengan tombol jbtOK
(baris 20). Ketika tombol OK ditekan, metode actionPerformed(ActionEvent) (baris 36) dalam OKListenerClass dipanggil untuk memproses event. Objek listener2 merupakan instans dari CancelListenerClass (baris 19), yang
didaftarkan dengan tombol jbtBatal
(baris 21). Ketika tombol Batal ditekan, metode actionPerformed(ActionEvent) (baris 42) dalam CancelListenerClass dipanggil untuk memproses event.
1.7
Contoh: Antarmuka Cloneable
Seringkali
diinginkan untuk menciptakan salinan dari suatu objek. Anda perlu menggunakan
metode clone dan memahami antarmuka Cloneable, yang merupakan topik bahasan
pada bagian ini.
Antarmuka
biasanya memuat konstanta-konstanta dan metode-metode abstrak, tetapi antarmuka
Cloneable merupakan kasus spesial.
Antarmuka Cloneable dalam paket java.lang didefinisikan sebagai
berikut:
package java.lang;
public interface Cloneable
{
}
Antarmuka
ini kosong. Suatu antarmuka kosong disebut dengan antarmuka penanda atau marker interface. Antarmuka penanda
tidak memuat konstanta dan metode. Antarmuka kosong digunakan untuk menandai
kelas yang memiliki properti khusus. Suatu kelas yang mengimplementasikan
antarmuka Cloneable dikatakan
klonabel, dan objeknya diklon menggunakan metode clone() yang didefinisikan dalam kelas Object.
Banyak
kelas dalam pustaka JAVA (misalnya, Calendar,
Date, dan ArrayList) mengimplementasikan Cloneable.
Jadi, instans-instans dari kelas-kelas tersebut dapat diklonkan. Misalnya, kode
berikut
1 Calendar kalender = new
GregorianCalendar(2003,
2, 1);
2 Calendar kalender1 = kalender;
3 Calendar kalender2 = (Calendar) kalender.clone();
4 System.out.println("kalender
== kalender1 adalah " +
5 (kalender == kalender1));
6 System.out.println("kalender
== kalender2 adalah " +
7 (kalender == kalender2));
8 System.out.println("kalendar.equals(kalendar2)
adalah " +
9 kalender.equals(kalender2));
menampilkan
kalender == kalender1 adalah true
kalender == kalender2 adalah false
kalender.equals(kalender2) adalah
true
Pada
kode sebelumnya, baris 2 menyalin referensi dari kelender kepada kalender1,
jadi kalender dan kelender1 sama-sama menunjuk kepada
objek Calendar yang sama. Baris 3
menciptakan suatu objek baru yang merupakan hasil klon dari kalender dan menugaskan referensi dari
objek baru itu kepada kalender2.
Sekarang, kalender2 dan kalender merupakan dua objek yang
berbeda yang memiliki isi sama.
Anda
bisa mengklon suatu array menggunakan metode clone(). Sebagai contoh, kode berikut
1 int[]
list1 = {1, 2};
2 int[]
list2 = list1.clone();
3 list1[0]
= 7; list1[1]
= 8;
4
5 System.out.println("list1
adalah " + list1[0]
+ ", " + list1[1]);
6 System.out.println("list2
adalah " + list2[0]
+ ", " + list2[1]);
menampilkan
list1 adalah 7, 8
list2 adalah 1, 2
Untuk
mendefinisikan kelas yang mengimplementasikan antarmuka Cloneable, kelas harus mengoverride metode clone() dalam kelas Object.
Kode1.9 mendefinisikan suatu kelas yang diberinama Rumah yang mengimplementasikan Cloneable
dan Comparable.
Kode1.9 Rumah.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
|
public class Rumah
implements Cloneable, Comparable{
private int id;
private double luas;
private java.util.Date kapanDibangun;
public Rumah(int id, double
luas) {
this.id = id;
this.luas = luas;
kapanDibangun = new
java.util.Date();
}
public int dapatId() {
return id;
}
public double dapatLuas() {
return luas;
}
public java.util.Date
dapatKapanDibangun() {
return kapanDibangun;
}
/** Mengoverride metode klon protected yang
didefinisikan dalam
kelas Object, dan memperkuat
aksesibilitasnya */
public
Object clone() throws CloneNotSupportedException {
return super.clone();
}
/** Mengimplementasikan metode compareTo,didefinisikan
dalam Comparable */
public int
compareTo(Object o) {
if (luas > ((Rumah)o).luas)
return 1;
else if (luas < ((Rumah)o).luas)
return -1;
else
return 0;
}
}
|
Kelas Rumah mengimplementasikan metode clone (baris 26-28) yang didefinisikan dalam kelas Object. Headernya adalah
protected
native Object clone() throws CloneNotSupportedException;
Katakunci
native mengindikasikan bahwa metode
ini tidak ditulis dalam JAVA tetapi diimplementasikan dalam JVM untuk platform
natif. Katakunci protected membatasi
metode agar hanya bisa diakses dari sesama paket atau dari subkelas. Karena
alasan ini, kelas Rumah harus
mengoverride metode clone menjadi public agar bisa diakses dari sembarang
paket. Karena metode clone yang diimplementasikan
untuk platform natif dalam kelas Object
melakukan tugas pengklonan objek, maka metode clone di dalam kelas Rumah
hanya ditujukan untuk memanggil super.clone().
Metode clone yang didefinisikan
dalam kelas Object bisa saja
melempar CloneNotSupportedException.
Kelas Rumah mengimplementasikan metode compareTo (baris 31-38) yang
didefinisikan dalam kelas Comparable.
Metode ini membandingkan luas dua rumah.
Gambar
1.6
Metode clone menyalin nilai-nilai bidang-bidang bertipe primitif dan
referensi-referensi bidang-bidang bertipe objek.
Anda
sekarang dapat menciptakan suatu objek dari kelas Rumah dan menciptakan suatu salinan identik dari objek tersebut,
sebagai berikut:
Rumah rumah1 = new
Rumah (1,
1750.50);
Rumah rumah2 = (House)
rumah1.clone();
rumah1 dan rumah2 adalah dua objek berbeda dengan
isi yang identik. Metode clone dalam
kelas Object menyalin setiap bidang
dari objek asli kepada objek target. Jika bidang bertipe primitif, maka
nilainya akan disalin. Sebagai contoh, nilai luas (bertipe double)
disalin dari rumah1 kepada rumah2. Jika bidang bertipe objek, maka
referensi bidang tersebut disalin. Sebagai contoh, bidang kapanDiciptakan bertipe Date,
jadi referensinya disalin kepada rumah, seperti
ditunjukkan pada Gambar 1.6. Oleh karena itu, rumah1.kapanDibangun == rumah2.kapanDibangun adalah true, meskipun rumah1 == rumah2 adalah false.
Hal ini dikenal dengan penyalinan dangkal atau shallow copy, bukan penyalinan dalam atau deep copy, yang berarti bahwa jika bidang bertipe objek, maka
referensi objek yang disalin, bukan isinya yang disalin.
1.8
Antarmuka versus Kelas Abstrak
Antarmuka
dapat digunakan kurang lebih sama dengan kelas abstrak, tetapi pendefinisian
antarmuka berbeda dari pendefinisian kelas abstrak. Tabel1.2 menyimpulkan
perbedaan-perbedaan antara keduanya.
JAVA
hanya mengijinkan pewarisan tunggal untuk pewarisan kelas tetapi mengijinkan
pewarisan jamak untuk antarmuka. Sebagai contoh,
public
class KelasBaru extends KelasBasis
implements Antarmuka1, ..., AntarmukaN{
...
}
Tabel
1.2 Antarmuka versi Kelas Abstrak
Variabel
|
Konstruktor
|
Metode
|
|
Kelas
abstrak
Antarmuka
|
Tidak ada pembatasan
Semua variabel harus public static final
|
Konstruktor dipanggil oleh subkelas melalui rantai
konstruktor. Kelas abstrak tidak bisa diinstansiasi menggunakan operator new.
Tidak ada konstruktor. Antarmuka tidak bisa
diinstansiasi menggunakan operator new.
|
Tidak Ada pembatasan
Semua metode harus berupa metode instans public abstract
|
Antarmuka dapat mewarisi antarmuka lain menggunakan katakunci extends. Antarmuka seperti itu disebut dikenal dengan sub-antarmuka atau subinterface. Misalnya, AntarmukaBaru pada kode berikut ini merupakan sub-antarmuka Antarmuka1, ..., dan AntarmukaN.
public
interface AntarmukaBaru extends Antarmuka1, ..., AntarmukaN {
// konstanta-konstanta dan metode-metode
abstrak
}
Suatu
kelas yang mengimplementasikan AntarmukaBaru
harus mengimplementasikan metode-metode abstrak yang didefinisikan dalam AntarmukaBaru,
Antarmuka1 ,..., dan AntarmukaN. Suatu antarmuka dapat mewarisi
antarmuka-antarmuka lain, tetapi tidak mewarisi kelas-kelas lain. Suatu kelas
dapat mewarisi superkelasnya dan mengimplementasikan antarmuka-antarmuka.
Semua
kelas memiliki akar yang sama, kelas Object,
tetapi tidak ada akar bagi antarmuka. Seperti kelas, antarmuka juga
mendefinisikan tipe. Variabel dari suatu tipe antarmuka dapat menunjuk kepada
sembarang instans dari kelas yang mengimplementasikan antarmuka. Jika suatu
kelas mengimplementasikan suatu antarmuka, maka antarmuka itu seperti superkelas
bagi kelas tersebut. Anda dapat menggunakan antarmuka sebagai tipe data dan
melakukan casting terhadap variabel bertipe antarmuka menjadi bertipe
subkelasnya, dan sebaliknya. Sebagai contoh, dimisalkan bahwa c adalah suatu instans dari Kelas2 pada Gambar 1.7, maka c juga merupakan instans dari Object, Kelas1, Interface1, Interface1_1, Interface1_2, Interface2_1,
dan Interface2_2.
Gambar
1.7 Kelas1 mengimplementasikan Interface1;
Interface1 mewarisi Interface1_1 dan Interface1_2. Kelas2
mewarisi Kelas1 dan
mengimplementasikan Interface2_1 dan
Interface2_2
Pada
umumnya, antarmuka lebih diinginkan dari kelas abstrak karena antarmuka dapat
mendefinisikan suatu supertipe umum untuk kelas-kelas yang tidak berelasi.
Antarmuka lebih fleksibel dari kelas. Pertimbangkan kelas Binatang. Dimisalkan bahwa metode bagaimanaMemakan didefinisikan di dalam kelas Binatang, sebagai berikut:
abstract
class Binatang {
public abstract String bagaimanaMemakan();
}
Dua
subkelas dari Binatang didefinisikan
sebagai berikut:
class
Ayam extends Binatang
{
public String bagaimanaMemakan (){
return "Goreng saja";
}
}
class
Bebek extends Binatang
{
public String bagaimanaMemakan(){
return "Panggang saja";
}
}
Dengan hirarki pewarisan ini, polimorfisme memampukan Anda untuk memuat suatu referensi kepada suatu objek Ayam atau objek Bebek di dalam suatu variabel bertipe Binatang, seperti ditunjukkan pada kode berikut ini:
public static void main(String[]
args) {
Binatang binatang = new
Ayam();
makan(binatang);
animal = new Bebek();
makan(binatang);
}
public static void makan(Binatang
binatang) {
binatang.bagaimanaMemakan();
}
JVM
secara dinamis memutuskan metode bagaimanaMemakan()
mana yang dipanggil berdasar pada objek aktual yang memanggil metode.
Antarmuka
tidak memiliki keterbatasan. Antarmuka memberikan Anda fleksibilitas yang lebih
daripada kelas, karena Anda tidak harus membuat segala sesuatu sesuai dengan
suatu tipe kelas. Anda bisa mendefinisikan metode bagaimanaMemakan di dalam suatu antarmuka dan membiarkannya
berperan sebagai supertipe bersama untuk kelas-kelas lain. Sebagai contoh,
public
static void main(String[]
args) {
Edible makanan = new Ayam();
makan(makanan);
makanan = new Bebek();
makan (makanan);
makanan = new Brokoli();
makan (makanan);
}
public
static void eat(Edible
makanan) {
makanan.bagaimanaMemakan();
}
interface
Edible {
public String bagaimanaMemakan ();
}
class
Ayam implements Edible
{
public String bagaimanaMemakan(){
return "Goreng
saja";
}
}
class
Bebek implements Edible {
public String bagaimanaMemakan (){
return "Panggang
saja";
}
}
class
Brokoli implements Edible {
public String bagaimanaMemakan (){
return "Rebus saja";
}
}
1.9
Memproses Nilai Bertipe Data Primitif Sebagai Objek
JAVA
menyediakan kelas-kelas wrapper,seperti Boolean,
Character, Double, Float, Byte, Short, Integer, dan Long untuk tipe-tipe primitif.
Kelas-kelas ini dikelompokkan dalam paket java.lang.
Hirarki pewarisannya ditampilkan pada Gambar 1.8.
Gambar
1.8 Kelas Number adalah superkelas abstrak bagi Double, Float, Byte, Short, Integer, dan Long
Setiap
kelas wrapper numerik mewarisi kelas abstrak Number, yang memuat metode-metode doubleValue(), floatValue(),
intValue(), longValue(), shortValue(),
dan byteValue(). Metode-metode ini
mengkonversi objek menjadi nilai bertipe primitif. Setiap kelas wrapper
mengoverride metode equals dan
metode toString yang didefinisikan
di dalam kelas Object. Karena semua
kelas wrapper mengimplementasikan antarmuka Comparable, maka metode compareTo
diimplementasikan dalam kelas-kelas tersebut.
Gambar
1.9 Kelas-kelas wrapper menyediakan
konstruktor,konstanta, dan metode konversi untuk memanipulasi berbagai tipe
data
Kelas-kelas
wrapper mirip satu sama lain. Bagian ini akan menggunakan Integer dan Double
sebagai contoh untuk mengenalkan kelas wrapper numerik. Fitur-fitur kunci dari Integer dan Double ditampilkan pada Gambar 1.9.
Anda
bisa menciptakan suatu objek wrapper dari nilai tipe data primitif atau dari
string yang merepresentasikan nilai numerik, misalnya new Double(5.0), new
Double(“5.0”), dan new Integer(“5”).
Kelas
wrapper tidak memiliki konstruktor tanpa-argumen. Instans dari semua kelas
wrapper adalah immutable; ini berarti bahwa begitu objek diciptakan, maka nilai
internalnya tidak dapat diubah.
Setiap
kelas wrapper numerik memiliki konstanta MAX_VALUE
dan MIN_VALUE. MAX_VALUE merepresentasikan nilai maksimum dari tipe data yang
diberikan. Untuk Byte, Short, Integer, dan Long, MIN_VALUE merepresentasikan nilai
minimum dari byte, short, int, dan long. Untuk Float dan Double, MIN_VALUE
merepresentasikan nilai positif minimum dari float dan double.
Statemen-statemen berikut ini menampilkan integer maksimum (2.147.283.647),
nilai minimum positif dari float
(1.4E-45), dan nilai pecahan maksimum double (1.79769313486231570e+308d)
System.out.println("Integer
maksimum adalah " + Integer.MAX_VALUE);
System.out.println("float
positif minimum adalah " +
Float.MIN_VALUE);
System.out.println("Pecahan
maksimum double adalah " +
Double.MAX_VALUE);
Setiap
kelas wrapper numerik mengimplementasikan metode-metode abstrak doubleValue(), floatValue(), intValue(),
longValue(), dan shortValue(), yang didefinisikan di
dalam kelas Number. Metode-metode
ini mengembalikan nilai double, float, int, long, atau short untuk objek wrapper.
Kelas-kelas
wrapper numerik memiliki suatu metode statik yang bermanfaat, valueOf(String s). Metode ini
menciptakan suatu objek baru yang diinisialisasi dengan nilai yang
direpresentasikan oleh string. Sebagai contoh,
Double objekDouble = Double.valueOf("12.4");
Integer objekInteger =
Integer.valueOf("12");
Anda
dapat menggunakan metode parseInt di
dalam kelas Integer untuk
mengkonversi suatu string numerik menjadi nilai int dan metode parseDouble
di dalam kelas Double untuk
mengkonversi suatu string numerik menjadi nilai double. Setiap kelas wrapper numerik memiliki dua metode parsing
teroverload untuk mengkonversi suatu string numerik menjadi nilai numerik
sesuai, berbasis 10 (desimal) atau berbasis sembarang radiks (misalnya 2 untuk
biner, 8 untuk oktal, 16 untuk heksadesimal). Metode-metode ini ditunjukkan
berikut ini:
// Kedua metode ini dalam kelas Byte
public static byte parseByte(String
s)
public static byte parseByte(String
s, int radix)
// Kedua metode ini dalam kelas
Short
public static short parseShort(String
s)
public static short parseShort(String
s, int radix)
// Kedua metode ini dalam kelas
Integer
public static int parseInt(String
s)
public static int parseInt(String
s, int radix)
// Kedua metode ini dalam kelas Long
public static long parseLong(String
s)
public static long parseLong(String
s, int radix)
// Kedua metode ini dalam kelas
Float
public static float parseFloat(String
s)
public static
float parseFloat(String s, int radix)
// Kedua metode ini dalam kelas
Double
public static double parseDouble(String
s)
public static
double parseDouble(String s, int radix)
Sebagai
contoh,
Integer.parseInt("11",
2) mengembalikan 3;
Integer.parseInt("12",
8) mengembalikan 10;
Integer.parseInt("13",
10) mengembalikan 13;
Integer.parseInt("1A",
16) mengembalikan 26;
Integer.parseInt(“12”,2)
akan menghasilkan suatu eksepsi runtime karena 12 bukan suatu angka biner.
1.10
Mengurutkan Array Objek
Contoh
ini menyajikan suatu metode statik generik untuk mengurutkan suatu array yang
memuat objek-objek komparabel. Objek-objek tersebut merupakan instans-instans
dari antarmuka Comparable, dan
dibandingkan menggunakan metode compareTo.
Metode tersebut dapat digunakan untuk mengurutkan array yang memuat sembarang
objek sepanjang kelasnya mengimplementasikan antarmuka Comparable.
Untuk
menguji metode tersebut, program mengurutkan array integer, array double, array
karakter, dan array string. Program ditampilkan pada Gambar 1.10.
Kode1.10 UrutGenerik.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
64
65
66
|
public class UrutGenerik {
public static void main(String[]
args) {
// Menciptakan suatu array Integer
Integer[] intArray = {new
Integer(2), new Integer(4),
new Integer(3)};
// Menciptakan suatu array Double
Double[] doubleArray = {new
Double(3.4), new Double(1.3),
new Double(-22.1)};
// Menciptakan suatu array Character
Character[] charArray = {new
Character('a'),
new Character('J'), new
Character('r')};
// Menciptakan suatu array String
String[] stringArray =
{"Vivian", "Kristina", "Butet"};
//
Mengurutkan array
urut(intArray);
urut(doubleArray);
urut(charArray);
urut(stringArray);
// Menampilkan array terurut
System.out.print("Objek-objek
Integer terurut: ");
printList(intArray);
System.out.print("Objek-objek
Double terurut: ");
printList(doubleArray);
System.out.print("Objek-objek
Character terurut: ");
printList(charArray);
System.out.print("Objek-objek
String terurut: ");
printList(stringArray);
}
/** Mengurutkan array yang memuat
objek-objek komparabel */
public static void urut(Comparable[] list){
Comparable minSekarang;
int indeksMinSekarang;
for (int i = 0; i <
list.length - 1; i++) {
// Menemukan maksimum dalam list[0..i]
minSekarang = list[i];
indeksMinSekarang = i;
for (int j = i + 1; j <
list.length; j++) {
if
(minSekarang.compareTo(list[j]) > 0) {
minSekarang = list[j];
indeksMinSekarang = j;
}
}
// Menukar list[i] dengan
list[indeksMinSekarang] jika diperlukan;
if (indeksMinSekarang != i) {
list[indeksMinSekarang] = list[i];
list[i] = minSekarang;
}
}
}
/** Menampilkan array objek */
public static void printList(Object[]
list) {
for (int i = 0; i <
list.length; i++)
System.out.print(list[i] + "
");
System.out.println();
}
}
|
Keluaran
Objek-objek
Integer terurut: 2 3 4
Objek-objek
Double terurut: -22.1 1.3 3.4
Objek-objek
Character terurut: J a r
Objek-objek
String terurut: Butet Kristina Vivian
Algoritma
untuk metode urut cukup sederhana,
yang mengurutkan array yang memuat sembarang tipe objek, jika dan hanya jika
objek-objek tersebut merupakan instans dari antarmuka Comparable.Ini merupakan contoh dari pemrograman generik.
Pemrograman generik memampukan metode untuk beroperasi pada argumen-argumen
bertipe generik, yang membuatnya dapat didaur-ulang dengan berbagai tipe.
Kelas-kelas
Integer, Double, Character, dan String mengimplementasikan Comparable,
sehingga objek-objek dari kelas-kelas tersebut dapat dibandingkan menggunakan
metode compareTo. Metode urut menggunakan metode compareTo untuk menentukan urutan
objek-objek di dalam array.
JAVA
menyediakan suatu metode statik sort
untuk mengurutkan suatu array yang memuat sembarang tipe objek di dalam kelas java.util.Array, jika dan hanya jika
semua elemen array adalah komparabel. Jadi, Anda bisa menggunakan kode berikut
ini untuk mengurutkan array:
java.util.Arrays.sort(intArray);
java.util.Arrays.sort(doubleArray);
java.util.Arrays.sort(charArray);
java.util.Arrays.sort(stringArray);
Array
adalah objek. Suatu array merupakan instans dari kelas Object.Jadi, jika A
merupakan subtipe dari B, maka
setiap instans dari A[] merupakan
instans dari B[]. Oleh karena itu,
statemen-statemen berikut ini adalah true:
new int[10]
instanceof Object
new Integer[10]
instanceof Object
new Integer[10]
instanceof Comparable[]
new Integer[10]
instanceof Number[]
new Number[10]
instanceof Object[]
1.11
Konversi Otomatis Antara Tipe Primitif dan Tipe
Kelas Wrapper
JAVA
mengijinkan tipe-tipe primitif dan tipe-tipe kelas wrapper untuk dikonversi
secara otomatis. Sebagai contoh, statemen pada (a) dapat disederhanakan menjadi
statemen pada (b) karena autoboxing:
Konversi
antara tipe primitif menjadi tipe objek wrapper dikenal dengan autoboxing. Konversi sebaliknya disebut
dengan unboxing. Perhatikan contoh
sebagai berikut:
1 Integer[] intArray = {1,
2, 3};
2
System.out.println(intArray[0]
+ intArray[1]
+ intArray[2]);
Pada
baris 1, nilai-nilai primitif 1, 2, dan 3 secara otomatis dikonversi menjadi
objek-objek new Integer(1), new Integer(2), dan new Integer(3). Pada baris 2,
objek-objek intArray[0], intArray[1], dan intArray[2] secara otomatis dikonversi menjadi nilai-nilai int
yang akan ditambahkan bersama.
1.12
Kelas BigInteger dan BigDecimal
Jika
Anda perlu menghitung angka-angka integer sangat besar atau nilai-nilai pecahan
presisi-tinggi, maka Anda dapat menggunakan kelas BigInteger dan BigDecimal
di dalam paket java.math. Keduanya
adalah kelas immutable. Kedua kelas
tersebut mewarisi kelas Number dan
mengimplementasikan antarmuka Comparable.
Integer terbesar tipe long adalah Long.MAX_VALUE (9223372036854775807).
Suatu instans dari BigInteger dapat
merepresentasikan integer dengan sembarang ukuran. Anda sekarang dapat
menggunakan new BigInteger(String) dan new BigDecimal(String)
untuk menciptakan instans dari BigInteger dan BigDecimal,
menggunakan metode-metode add, subtract, multiple, divide,
dan remainder untuk melakukan operasi-operasi aritmatik, dan menggunakan
metode compareTo untuk membandingkan dua integer besar. Sebagai contoh,
kode berikut menciptakan dua objek BigInteger dan mengalikan keduanya:
BigInteger a = new
BigInteger("9223372036854775807");
BigInteger b = new
BigInteger("2");
BigInteger c = a.multiply(b); //
9223372036854775807 * 2
System.out.println(c);
Keluarannya adalah 18446744073709551614.
Tidak
ada batasan kepresisian untuk objek BigDecimal.
Metode divide dapat melemparkan eksepsi ArithmeticException
jika hasil tidak dapat dihentikan. Akan tetapi, Anda bisa menggunakan metode
teroverload divide(BigDecimal d, int skala,
int modePembulatan) untuk menentukan skala dan mode pembulatan untuk
menghindari eksepsi ini, dimana skala
adalah jumlah dijit minimum setelah titik desimal. Sebagai contoh, kode berikut
menciptakan dua objek BigDecimal dan
melakukan pembagian dengan skala 20
dan mode pembulatan BigDecimal.ROUND_UP.
BigDecimal a = new
BigDecimal(1.0);
BigDecimal b = new
BigDecimal(3);
BigDecimal c = a.divide(b, 20,
BigDecimal.ROUND_UP);
System.out.println(c);
Keluarannya
adalah 0.33333333333333333334. Perhatikan bahwa hasil faktorial atas suatu integer
dapat menjadi sangat besar. Kode1.11 memberikan suatu metode untuk menghasilkan
faktorial atas sembarang integer.
Kode1.11 FaktorialBesar.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import java.math.*;
public class FaktorialBesar {
public static void main(String[]
args) {
System.out.println("50! adalah
\n" + faktorial(50));
}
public static BigInteger faktorial(long
n) {
BigInteger result = BigInteger.ONE;
for (int i = 1; i <= n;
i++)
result = result.multiply(new BigInteger(i + ""));
return result;
}
}
|
Keluaran
50!
adalah
30414093201713378043612608166064768844377641568960512000000000000
BigInteger.ONE (baris
9) adalah suatu konstanta yang didefinisikan di dalam kelas BigInteger. BigInteger.ONE sama dengan new
BigInteger(“1”).
1.13
Studi Kasus: Kelas Rasional
Suatu
bilangan rasional memiliki pembilang dan penyebut dalam format a/b, dimana a adalah pembilang dan b
adalah penyebut. Sebagai contoh, 3/4, 6/7, dan 9/8 adalah
angka-angka rasional.
Suatu
bilangan rasional tidak dapat memiliki penyebut 0, tetapi jika pembilangnya 0
tidak masalah. Setiap integer i
ekivalen dengan angka rasional i/1.
Bilangan rasional dipakai dalam komputasi eksak yang melibatkan pecahan,
misalnya 1/3 = 0.3333333.... Angka
ini tidak bisa secara presisi direpresentasikan dalam format pecahan
menggunakan tipe data float ataupun double. Untuk mendapatkan hasil yang
eksak, digunakan angka rasional.
JAVA
menyediakan tipe-tipe data integer dan tipe-tipe data pecahan, tetapi tidak
menyediakan tipe data rasional. Bagian ini akan menunjukkan bagaimana mendesain
suatu kelas yang merepresentasikan bilangan rasional.
Karena
bilangan rasional memiliki fitur-fitur yang sama dengan integer dan angka
pecahan, dan karena Number merupakan
kelas akar bagi kelas-kelas wrapper, maka akan sesuai bila mendefinisikan kelas
Rasional menjadi subkelas dari Number. Karena angka rasional adalah
komparabel, maka kelas Rasional
harus mengimplementasikan antarmuka Comparable.
Gambar 1.10 mengilustrasikan kelas Rasional
dan relasinya dengan kelas Number
dan antarmuka Comparable.
Ada
banyak angka-angka rasional ekivalen, seperti 1/3 = 2/6 = 3/9 = 4/12. Pembagi
dan pembilang dari 1/3 tidak memiliki pembagi bersama kecuali 1, jadi 1/3
dikatakan dengan suku terendah.
Untuk
mereduksi suatu angka rasional menjadi suku terendahnya, Anda perlu mencari GCD
(greates common divisor, pembagi
bersama terbesar), kemudian membagi kedua pembilang dan penyebut dengan nilai
GCD tersebut. Kode1.12 menyajikan suatu program uji untuk menciptakan dua objek
Rasional dan menguji metode-metode yang disediakan.
Kode1.12 UjiKelasRasional.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
public class UjiKelasRasional {
/** Metode utama */
public static void main(String[]
args) {
// Menciptakan dan menginisialisasi dua
angka rasional r1 dan r2.
Rasional r1 = new Rasional(4, 2);
Rasional r2 = new Rasional(2, 3);
//
Menampilkan hasil-hasil
System.out.println(r1
+ " + " + r2 + " = " + r1.add(r2));
System.out.println(r1 + " - " +
r2 + " = "+ r1.subtract(r2));
System.out.println(r1 + " * " +
r2 + " = "+ r1.multiply(r2));
System.out.println(r1 + " / " +
r2 + " = "+ r1.divide(r2));
System.out.println(r2 + " adalah
"+ r2.doubleValue());
}
}
|
Keluaran
2 + 2/3
= 8/3
2 - 2/3
= 4/3
2 * 2/3
= 4/3
2 / 2/3
= 3
2/3 adalah
0.6666666666666666
Metode main menciptakan dua angka rasional, r1 dan r2 (baris 5-6), dan menampilkan hasil-hasil r1+r2, r1-r2, r1xr2, dan r1/r2 (baris 9-12). Untuk melakukan r1+r2, metode r1.add(r2)
dipanggil untuk mengembalikan suatu objek Rasional
yang baru. Dengan cara yang sama, r1.subtract(r2)
adalah untuk r1-r2, r1.multiply(r2) untuk r1xr2, dan r1.divide(r2) untuk r1/r2.
Metode doubleValue() menampilkan nilai double
dari r2 (baris 13). Metode tersebut
didefinisikan dalam java.lang.Number
dan telah dioverride di dalam Rasional.
Perhatikan
bahwa ketika suatu string disambungkan dengan objek menggunakan tanda plus (+), representasi string objek dari
metode toString() digunakan untuk
menyambung dengan string. Jadi, r1 + “ +
" + r2 + " = " +
r1.add(r2) ekivalen dengan r1.toString()
+ " + " + r2.toString() + " = " + r1.add(r2).toString(). Kelas
Rasional diimplementasikan dalam kode1.13.
Kode1.13 Rasional.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
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
|
public class Rasional extends Number implements
Comparable{
// Bidang-bidang data untuk pembilang dan
penyebut
private long pembilang = 0;
private long penyebut = 1;
/** Menciptakan suatu angka rasional dengan
properti default */
public
Rasional(){
this(0, 1);
}
/** Menciptakan suatu rasional dengan
pembilang and penyebut tertentu*/
public
Rasional(long pembilang, long penyebut){
long gcd = gcd(pembilang,
penyebut);
this.pembilang = ((penyebut > 0)
? 1 : -1) * pembilang / gcd;
this.penyebut = Math.abs(penyebut)
/ gcd;
}
/** Menemukan GCD atas dua angka */
private static long gcd(long
n, long d) {
long n1 = Math.abs(n);
long n2 = Math.abs(d);
int gcd = 1;
for (int k = 1; k <= n1
&& k <= n2; k++) {
if (n1 % k == 0 && n2 % k
== 0)
gcd = k;
}
return gcd;
}
/** Mengembalikan pembilang */
public long dapatPembilang() {
return pembilang;
}
/** Mengembalikan penyebut */
public long dapatPenyebut() {
return penyebut;
}
/** Menambahkan suatu angka rasional kepada
rasional ini */
public
Rasional add(Rasional rasionalKedua){
long n = pembilang *
rasionalKedua.dapatPenyebut() +
penyebut *
rasionalKedua.dapatPembilang();
long d = penyebut *
rasionalKedua.dapatPenyebut();
return new Rasional(n, d);
}
/** Mengurangi suatu angka rasional dari
rasional ini */
public
Rasional subtract(Rasional rasionalKedua){
long n = pembilang *
rasionalKedua.dapatPenyebut()
- penyebut *
rasionalKedua.dapatPembilang();
long d = penyebut *
rasionalKedua.dapatPenyebut();
return new Rasional(n, d);
}
/**
Mengalikan suatu angka rasional dengan rasional ini */
public Rasional multiply(Rasional
rasionalKedua){
long n = pembilang *
rasionalKedua.dapatPembilang();
long d = penyebut *
rasionalKedua.dapatPenyebut();
return new Rasional(n, d);
}
/**
Membagi suatu angka rasional dari rasional ini */
public Rasional divide(Rasional
rasionalKedua){
long n = pembilang *
rasionalKedua.dapatPenyebut();
long d = penyebut *
rasionalKedua.pembilang;
return new Rasional(n, d);
}
/** Mengoverride metode toString() */
public String toString() {
if (penyebut == 1)
return pembilang + "";
else
return pembilang + "/"
+ penyebut;
}
/** Mengoverride metode equals dalam kelas
Object */
public boolean equals(Object parm1) {
if ((this.subtract((Rasional)(parm1))).dapatPembilang()
== 0)
return true;
else
return false;
}
/** Mengimplementasikan metode abstrak intValue
dalam java.lang.Number */
public int intValue() {
return (int)doubleValue();
}
/** Mengimplementasikan metode abstrak
floatValue dalam java.lang.Number */
public float floatValue() {
return (float)doubleValue();
}
/** Mengimplementasikan metode abstrak
doubleValue dalam java.lang.Number */
public double doubleValue() {
return pembilang * 1.0 / penyebut;
}
/** Mengimplementasikan metode abstrak
longValue dalam java.lang.Number */
public long longValue() {
return (long)doubleValue();
}
/** Mengimplementasikan metode compareTo
dalam java.lang.Comparable */
public int compareTo(Object o) {
if
((this.subtract((Rasional)o)).dapatPembilang() > 0)
return 1;
else if
((this.subtract((Rasional)o)).dapatPembilang() < 0)
return -1;
else
return 0;
}
}
|
thanks gan sudah share
ReplyDeletepinset bengkok