13
Pemrograman
Generik
Istilah
generik berarti tipe terparameterisasi. Tipe terparameterisasi penting karena
ia memampukan Anda untuk menciptakan kelas, antarmuka, dan metode dimana di
dalamnya tipe data ditetapkan sebagai parameter. Dengan generik, adalah
memungkinkan untuk menciptakan satu kelas yang secara otomatis dapat dipakai
untuk pelbagai tipe.
Soal dan
Penyelesaian
1.
Tulislah sebuah program yang mendefinisikan dua kelas. Yang pertama
adalah kelas Gen, dan kelas kedua
adalah DemoGen, yang menggunakan Gen.
Penyelesaian
// Sebuah kelas generik sederhana.
// Di sini, T merupakan parameter tipe yang
// akan digantikan oleh tipe riil
// ketika sebuah objek bertipe Gen diciptakan.
clabss Gen<T> {
T ob; // mendeklarasikan sebuah
objek bertipe T
// Melewatkan sebuah referensi
yang menunjuk ke objek bertipe T
// kepada konstruktor
Gen(T o) {
ob = o;
}
// Menghasilkan ob.
T getob() {
return ob;
}
// Menampilkan tipe dari T.
void tampilTipe() {
System.out.println("Tipe dari T adalah " +
ob.getClass().getName());
}
}
// Mendemonstrasikan kelas generik.
public class
DemoGen {
public static void main(String args[]) {
// Menciptakan sebuah
referensi Gen untuk Integer.
Gen<Integer> iOb;
// Menciptakan sebuah objek
Gen<Integer> dan menugaskan referensinya
// kepada iOb. Perhatikan
penggunaan autoboxing
// untuk mengenkapsulasi
nilai 88 di dalam sebuah objek Integer.
iOb = new Gen<Integer>(88);
// Menampilkan tipa data
yang digunakan oleh iOb.
iOb.tampilTipe();
// Mendapatkan nilai di
dalam iOb. Perhatikan bahwa
// tidak perlu cast.
int v = iOb.getob();
System.out.println("nilai: " + v);
System.out.println();
// Menciptakan sebuah objek
Gen untuk String.
Gen<String> strOb = new
Gen<String>("Test Generik");
// Menampilkan tipa data
yang digunakan oleh strOb.
strOb.tampilTipe();
// Mendapatkan nilai dari
strOb. Sekali lagi, perhatikan bahwa
// cast tidak diperlukan.
String str = strOb.getob();
System.out.println("nilai: " + str);
}
}
Keluaran Program
Tipe dari T adalah java.lang.Integer
nilai: 88
Tipe dari T adalah java.lang.String
nilai: Test Generik
2.
Anda dapat mendeklarasikan lebih dari satu parameter tipe di dalam tipe generik.
Untuk menetapkan dua atau lebih parameter tipe, Anda cukup menggunakan daftar
(menggunakan koma sebagai pimsah). Tulislah sebuah program untuk
mengilustrasikan situasi ini.
Penyelesaian
// Sebuah kelas generik sederhana dengan dua
// tipe parameter: T dan V.
class DuaGen<T, V> {
T ob1;
V ob2;
// Melewatkan kepada konstruktor
sebuah referensi yang menunjuk ke
// sebuah objek bertipe T dan
sebuah objek bertipe V.
DuaGen(T o1, V o2) {
ob1 = o1;
ob2 = o2;
}
// Menampilkan tipe dari T dan
V.
void tampilTipe() {
System.out.println("Tipe dari T adalah " +
ob1.getClass().getName());
System.out.println("Tipe dari V adalah " +
ob2.getClass().getName());
}
T getob1() {
return ob1;
}
V getob2() {
return ob2;
}
}
public class
GenerikSederhana {
public static void main(String args[]) {
DuaGen<Integer, String> tgObj =
new DuaGen<Integer, String>(88, "Generik");
// Menampilkan tipe-tipe.
tgObj.tampilTipe();
// medapatkan dan
menampilkan nilai-nilai.
int v = tgObj.getob1();
System.out.println("nilai: " + v);
String str = tgObj.getob2();
System.out.println("nilai: " + str);
}
}
Keluaran Program
Tipe dari T adalah java.lang.Integer
Tipe dari V adalah java.lang.String
nilai: 88
nilai: Generik
3.
Pada dua soal sebelumnya, parameter tipe dapat digantikan oleh tipe
kelas apapun. Ini baik untuk banyak kasus, tetapi kadangkala Anda perlu
membatasi tipe-tipe apa saja yang dapat dilewatkan kepada sebuah parameter
tipe. Dimisalkan bahwa Anda ingin menciptakan sebuah kelas generik yang memuat
sebuah metode yang menghasilkan rerata dari sebuah array yang memuat
angka-angka. Selanjutnya, Anda ingin menggunakan kelas untuk mendapatkan rerata
tersebut untuk angka-angka dengan tipe-tipe data numerik, termasuk integer,
float, dan double.
Untuk menangani situasi semacam ini,
Java menyediakan klausa extends
ketika penetapan parameter tipe dilakukan. Tulislah sebuah program untuk
mengilustrasikan situasi ini.
Penyelesaian
// Pada program ini, argumen tipe untuk T
// haruslah Number, atau sebuah kelas yang diderivasi
// dari Number.
class Stats<T extends Number>
{
T[] arrayAngka; // array Number
atau subkelas bertipe Number
// Melewatkan kepada konstruktor
sebuah referensi yang menunjuk ke
// sebuah array atau subkelas
bertipe Number.
Stats(T[] o) {
arrayAngka = o;
}
// Menghasilkan tipe double pada
semua kelas.
double rerata() {
double jum = 0.0;
for(int i=0; i <
arrayAngka.length; i++)
jum +=
arrayAngka[i].doubleValue();
return jum / arrayAngka.length;
}
}
public class
DemoGenerikTerkekang {
public static void main(String args[]) {
Integer arrayInteger[] = {
1, 2, 3, 4, 5 };
Stats<Integer> iob = new Stats<Integer>(arrayInteger);
double v = iob.rerata();
System.out.println("rerata iob average adalah " + v);
Double arrayDouble[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Double> dob = new Stats<Double>(arrayDouble);
double w = dob.rerata();
System.out.println("rerata dob adalah " + w);
// Ini tidak bisa
dikompilasi karena String bukanlah
// subkelas dari Number.
// String arrayString[] = {
"1", "2", "3", "4", "5" };
// Stats<String> strob
= new Stats<String>(arrayString);
// double x =
strob.average();
//
System.out.println("rerata strob adalah " + v);
}
}
Keluaran Program
rerata iob average adalah 3.0
rerata dob adalah 3.3
4.
Diberikan kelas Stats seperti
pada soal no 3 dan diasumsikan bahwa Anda ingin menambahkan sebuah metode
bernama rerataSama yang menentukan
apakah dua objek Stats memuat
array-array dengan nilai reraya sama, tanpa memandang tipe dari data numeri
pada tiap objek. Sebagai contoh, jika satu objek memuat nilai-nilai double 1.0,
2.0, dan 3.0, dan objek lain memuat nilai-nilai integer 2, 1, dan 3, maka
reratanya akan sama. Tulislah sebuah program untuk mengilustrasikan situasi ini.
Penyelesaian
class Stats<T extends Number>
{
T[] arrayAngka; // array of
Number or subclass
// Melewatkan kepada konstruktor
sebuah referensi yang menunjuk ke
// sebuah array atau subkelas
bertipe Number.
Stats(T[] o) {
arrayAngka = o;
}
// Menghasilkan tipe double pada
semua kelas.
double rerata() {
double jum = 0.0;
for(int i=0; i <
arrayAngka.length; i++)
jum += arrayAngka[i].doubleValue();
return jum / arrayAngka.length;
}
// Menentukan jika dua rerata
sama.
// Perhatikan penggunaan
wildcard (?).
boolean rerataSama(Stats<?>
ob) {
if(rerata() == ob.rerata())
return true;
return false;
}
}
public class
DemoGenerik {
public static void main(String args[]) {
Integer arrayInteger[] = { 1, 2, 3, 4, 5 };
Stats<Integer> iob = new Stats<Integer>(arrayInteger);
double v = iob.rerata();
System.out.println("rerata iob adalah " + v);
Double arrayDouble[] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
Stats<Double> dob = new Stats<Double>(arrayDouble);
double w = dob.rerata();
System.out.println("rerata dob adalah " + w);
Float arrayFloat[] = { 1.0F, 2.0F, 3.0F, 4.0F, 5.0F };
Stats<Float> fob = new Stats<Float>(arrayFloat);
double x = fob.rerata();
System.out.println("rerata fob adalah " + x);
// Melihat apakah array
memiliki rerata sama.
System.out.print("Rerata dari iob dan dob ");
if(iob.rerataSama(dob))
System.out.println("adalah
sama.");
else
System.out.println("berbeda.");
System.out.print("Rerata dari iob dan fob ");
if(iob.rerataSama(fob))
System.out.println("adalah
sama.");
else
System.out.println("berbeda.");
}
}
Keluaran Program
rerata iob adalah 3.0
rerata dob adalah 3.3
rerata fob adalah 3.0
Rerata dari iob dan dob berbeda.
Rerata dari iob dan fob adalah sama.
5.
Tulislah sebuah program lain untuk mendemonstrasikan pengekangan
argumen, seperti pengekangan parameter.
Penyelesaian
// Argumen Wildcard terkekang.
// Koordinat dua-dimensi.
class DuaD {
int x, y;
DuaD(int a, int b) {
x = a;
y = b;
}
}
// Koordinat tiga-dimensi.
class TigaD extends DuaD {
int z;
TigaD(int a, int b, int c) {
super(a, b);
z = c;
}
}
// Koordinat empat-dimensi.
class EmpatD extends TigaD {
int t;
EmpatD(int a, int b, int c, int d) {
super(a, b, c);
t = d;
}
}
// Kelas ini memuat sebuah array yang memuat objek-objek koordinat.
class Koordinat<T extends
DuaD> {
T[] arrayKoord;
Koordinat(T[] o) { arrayKoord =
o; }
}
// Mendemonstrasikan wildcar terkekang.
public class
DemoPengekanganArgumen {
static void
tampilXY(Koordinat<?> c) {
System.out.println("Koordinat X Y:");
for(int i=0; i <
c.arrayKoord.length; i++)
System.out.println(c.arrayKoord[i].x + " " +
c.arrayKoord[i].y);
System.out.println();
}
static void
tampilXYZ(Koordinat<? extends
TigaD> c) {
System.out.println("Koordinat X Y Z:");
for(int i=0; i <
c.arrayKoord.length; i++)
System.out.println(c.arrayKoord[i].x + " " +
c.arrayKoord[i].y + "
" +
c.arrayKoord[i].z);
System.out.println();
}
static void tampilSemua(Koordinat<?
extends EmpatD> c) {
System.out.println("Koordinat X Y Z T:");
for(int i=0; i <
c.arrayKoord.length; i++)
System.out.println(c.arrayKoord[i].x + " " +
c.arrayKoord[i].y +
" " +
c.arrayKoord[i].z +
" " +
c.arrayKoord[i].t);
System.out.println();
}
public static void main(String args[]) {
DuaD td[] = {
new DuaD(0, 0),
new DuaD(7, 9),
new DuaD(18, 4),
new DuaD(-1, -23)
};
Koordinat<DuaD> lokasi
= new Koordinat<DuaD>(td);
System.out.println("Isi dari lokasi.");
tampilXY(lokasi); // OK,
merupakan objek DuaD
// tampilXYZ(lokasi); //
Error, bukan objek TigaD
// tampilSemua(lokasi); //
Error, bukan objek EmpatD
// Sekarang, menciptakan
empat objek EmpatD.
EmpatD fd[] = {
new EmpatD(1, 2, 3, 4),
new EmpatD(6, 8, 14, 8),
new EmpatD(22, 9, 4, 9),
new EmpatD(3, -2, -23, 17)
};
Koordinat<EmpatD>
lokasi2 = new
Koordinat<EmpatD>(fd);
System.out.println("Isi dari lokasi2.");
// Semua ini OK.
tampilXY(lokasi2);
tampilXYZ(lokasi2);
tampilSemua(lokasi2);
}
}
Keluaran Program
Isi dari lokasi.
Koordinat X Y:
0 0
7 9
18 4
-1 -23
Isi dari lokasi2.
Koordinat X Y:
1 2
6 8
22 9
3 -2
Koordinat X Y Z:
1 2 3
6 8 14
22 9 4
3 -2 -23
Koordinat X Y Z T:
1 2 3 4
6 8 14 8
22 9 4 9
3 -2 -23 17
6.
Tulislah sebuah program yang menggunakan metode generik.
Penyelesaian
// Demonstrasi sebuah metode generik sederhana.
public class
DemoMetodeGenerik {
// Menentukan apakah sebuah
objek ada di dalam suatu array.
static <T, V extends
T> boolean ApaDiDalam(T x, V[] y)
{
for(int i=0; i <
y.length; i++)
if(x.equals(y[i])) return
true;
return false;
}
public static void main(String args[]) {
// Menggunakan ApaDiDalam()
pada Integer.
Integer arrayAngka[] = { 1, 2, 3, 4, 5 };
if(ApaDiDalam(2, arrayAngka))
System.out.println("2 ada di
dalam arrayAngka");
if(!ApaDiDalam(7, arrayAngka))
System.out.println("7 ada di
dalam arrayAngka");
System.out.println();
// Menggunakan ApaDiDalam()
pada String.
String arrayString[] = {
"satu", "dua", "tiga",
"empat", "lima" };
if(ApaDiDalam("dua",
arrayString))
System.out.println("dua
adalah di dalam arrayString");
if(!ApaDiDalam("tujuh",
arrayString))
System.out.println("tujuh
tidak ada di dalam arrayString");
// Tidak bisa dikompilasi!
Tipe-tipe harus kompatibel.
// if(arrayString("dua
arrayAngka))
//
System.out.println("dua adalah di dalam arrayString");
}
}
Keluaran Program
2 ada di dalam arrayAngka
7 ada di dalam arrayAngka
dua adalah di dalam arrayString
tujuh tidak ada di dalam arrayString
7.
Adalah memungkinkan untuk konstruktor menjadi generik, meskipun kelasnya
tidak generik. Tulislah sebuah program yang mengilustrasikan situasi ini.
Penyelesaian
// Menggunakan sebuah konstruktor generik.
class KonstruktorGenerik {
private double nil;
<T extends Number> KonstruktorGenerik(T arg) {
nil = arg.doubleValue();
}
void tampilNil() {
System.out.println("nilai: " + nil);
}
}
public class DemoKonstruktorGenerik
{
public static void main(String args[]) {
KonstruktorGenerik test = new KonstruktorGenerik(100);
KonstruktorGenerik test2 = new KonstruktorGenerik(123.5F);
test.tampilNil();
test2.tampilNil();
}
}
Keluaran Program
nilai: 100.0
nilai: 123.5
8.
Selain kelas dan metode generik, Anda juga dapat memiliki antarmuka
generik. Antarmuka generik ditetapkan sama seperti kelas generik. Tulislah
sebuah program yang mengilustrasikan situasi ini.
Penyelesaian
// Antarmuka MinMaks.
interface MinMaks<T extends
Comparable<T>> {
T min();
T maks();
}
// Sekarang, mengimplementasikan MinMaks
class KelasKu<T extends
Comparable<T>> implements
MinMaks<T> {
T[] arrayNilai;
KelasKu(T[] o) { arrayNilai = o;
}
// Menghasilkan nilai minimum di
dalam arrayNilai.
public T min() {
T v = arrayNilai[0];
for(int i=1; i <
arrayNilai.length; i++)
if(arrayNilai[i].compareTo(v) < 0) v = arrayNilai[i];
return v;
}
// Menghasilkan nilai maksimum
di dalam arrayNilai.
public T maks() {
T v = arrayNilai[0];
for(int i=1; i <
arrayNilai.length; i++)
if(arrayNilai[i].compareTo(v) > 0) v = arrayNilai[i];
return
v;
}
}
public class
DemoAntarmukaGenerik {
public static void main(String args[]) {
Integer arrayInteger[] = {3,
6, 2, 8, 6 };
Character arrayKarakter[] =
{'b', 'r', 'p', 'w' };
KelasKu<Integer> iob = new KelasKu<Integer>(arrayInteger);
KelasKu<Character> cob = new KelasKu<Character>(arrayKarakter);
System.out.println("Nilai maks di dalam arrayInteger: "
+ iob.maks());
System.out.println("Nilai min di dalam arrayInteger: "
+ iob.min());
System.out.println("Nilai maks di dalam arrayKarakter:
" + cob.maks());
System.out.println("Nilai min di dalam arrayKarakter:
" + cob.min());
}
}
Keluaran Program
Nilai maks di dalam arrayInteger: 8
Nilai min di dalam arrayInteger: 2
Nilai maks di dalam arrayKarakter: w
Nilai min di dalam arrayKarakter: b
9.
Kelas-kelas generik dapat menjadi bagian dari hirarki pewarisan kelas
sama seperti kelas tak-generik. Jadi, sebuah kelas generik dapat berperan
sebagai superkelas atau sebagai subkelas. Perbedaan kunci antara hirarki
generik dan hirarki tak-generik adalah bahwa di dalam hirarki generik, setiap
argumen tipe yang diperlukan oleh superkelas generik harus dilewatkan ke atas
hirarki oleh semua subkelas. Ini sama dengan ketika argumen-argumen konstruktor
dilewatkan ke atas hirarki. Tulislah sebuah program yang mengilustrasikan
situasi ini.
Penyelesaian
// Sebuah subkelas dapat menambahkan parameter tipenya sendiri.
class Gen<T> {
T ob; // mendeklarasikan sebuah
objek bertipe T
// Melewatkan kepada konstruktor
sebuah referensi yang menunjuk ke
// sebuah objek bertipe T.
Gen(T o) {
ob = o;
}
// Menghasilkan ob.
T getob() {
return ob;
}
}
// Sebuah subkelas dari Gen yang mendefinisikan
// parameter tipe kedua, dinamakan V.
class Gen2<T, V> extends
Gen<T> {
V ob2;
Gen2(T o, V o2) {
super(o);
ob2 = o2;
}
V getob2() {
return ob2;
}
}
// Menciptakan sebuah objek bertipe Gen2.
public class
DemoPewarisanGenerik {
public static void main(String args[]) {
// Menciptakan sebuah objek
Gen2 untuk String dan Integer.
Gen2<String, Integer> x =
new Gen2<String, Integer>("Nilai adalah: ",
99);
System.out.print(x.getob());
System.out.println(x.getob2());
}
}
Keluaran Program
Nilai adalah: 99
10. Adalah hal yang
memungkinkan bagi kelas tak-generik menjadi superkelas bagi subkelas generik.
Tulislah sebuah program yang mengilustrasikan situasi ini.
Penyelesaian
// Sebuah kelas tak-generik dapat menjadi superkelas
// bagi subkelas generik.
// Sebuah kelas tak-generik.
class TakGen {
int angka;
TakGen(int i) {
angka = i;
}
int getAngka() {
return angka;
}
}
// Sebuah subkelas generik.
class Gen<T> extends TakGen {
T ob; // mendeklarasikan sebuah
objek bertipe T
// Melewatkan konstruktor sebuah
referensi yang menunjuk ke
// sebuah objek bertipe T.
Gen(T o, int i) {
super(i);
ob = o;
}
// Menghasilkan ob.
T getob() {
return ob;
}
}
// Menciptakan sebuah objek Gen.
public class
DemoPewarisanGenerik2 {
public static void main(String args[]) {
// Menciptakan sebuah objek
Gen bertipe String.
Gen<String> w = new
Gen<String>("Selamat Malam", 47);
System.out.print(w.getob() +
" ");
System.out.println(w.getAngka());
}
}
Keluaran Program
Selamat Malam 47
11. Sebuah metode generik
di dalam suatu kelas generik dapat didefinisikan-ulang sama seperti metode lainnya.
Tulislah sebuah program yang mengilustrasikan situasi ini.
Penyelesaian
// Mendefinisikan-ulang sebuah metode generik di dalam kelas generik.
class Gen<T> {
T ob; // mendeklarasikan sebuah
objek bertipe T
// Melewatkan kepada konstruktor
sebuah referensi yang menunjuk ke
// sebuah objek bertipe T.
Gen(T o) {
ob = o;
}
// menghasilkan ob.
T getob() {
System.out.print("metode getob() dari kelas Gen: "
);
return ob;
}
}
// Sebuah subkelas dari Gen yang mendefinisikan-ulang getob().
class Gen2<T> extends
Gen<T> {
Gen2(T o) {
super(o);
}
// Mendefinisikan-ulang getob().
T getob() {
System.out.print("metode getob() dan kelas Gen2: ");
return ob;
}
}
// Mendemonstrasikan pendefinisian-ulang metode generik.
public class
DemoDefinisiUlangMetodeGenerik {
public static void main(String args[]) {
// Menciptakan sebuah objek
Gen untuk Integer.
Gen<Integer> iOb = new
Gen<Integer>(88);
// Menciptakan sebuah objek
Gen2 untuk Integer.
Gen2<Integer> iOb2 = new
Gen2<Integer>(99);
// Menciptakan sebuah objek
Gen2 untuk String.
Gen2<String> strOb2 = new Gen2<String>("Test Generik");
System.out.println(iOb.getob());
System.out.println(iOb2.getob());
System.out.println(strOb2.getob());
}
}
Keluaran Program
metode getob() dari kelas Gen: 88
metode getob() dan kelas Gen2: 99
metode getob() dan kelas Gen2: Test Generik
No comments:
Post a Comment