CodeGym /Java Blog /Acak /Generik di Jawa
John Squirrels
Level 41
San Francisco

Generik di Jawa

Dipublikasikan di grup Acak
Hai! Kita akan berbicara tentang Generik Java. Saya harus mengatakan bahwa Anda akan belajar banyak! Tidak hanya pelajaran ini, tetapi juga beberapa pelajaran berikutnya, akan dikhususkan untuk obat generik. Jadi, jika Anda tertarik dengan obat generik, hari ini adalah hari keberuntungan Anda: Anda akan belajar banyak tentang fitur obat generik. Dan jika tidak, pasrah dan santai! :) Ini adalah topik yang sangat penting, dan Anda perlu mengetahuinya. Mari kita mulai dengan yang sederhana: "apa" dan "mengapa".

Apa itu Generik Java?

Generik adalah tipe yang memiliki parameter. Saat membuat tipe generik, Anda tidak hanya menentukan tipe, tetapi juga tipe data yang akan digunakan. Saya menduga contoh yang paling jelas sudah muncul di benak Anda: ArrayList! Inilah cara kami biasanya membuatnya dalam sebuah program:

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<String> myList1 = new ArrayList<>();
       myList1.add("Test String 1");
       myList1.add("Test String 2");
   }
}
Seperti yang Anda duga, fitur dari daftar ini adalah kita tidak dapat memasukkan semuanya ke dalamnya: ini bekerja secara eksklusif dengan objek String . Sekarang mari kita sedikit menyimpang ke dalam sejarah Jawa dan mencoba menjawab pertanyaan "mengapa?" Untuk melakukannya, kita akan menulis kelas ArrayList versi sederhana kita sendiri. Daftar kami hanya mengetahui cara menambahkan data ke dan mengambil data dari larik internal:

public class MyListClass {

   private Object[] data;
   private int count;

   public MyListClass() {
       this.data = new Object[10];
       this.count = 0;
   }

   public void add(Object o) {
       this.data[count] = o;
       count++;
   }

   public Object[] getData() {
       return data;
   }
}
Misalkan kita ingin daftar kita hanya menyimpan Integer s. Kami tidak menggunakan tipe generik. Kami tidak ingin menyertakan cek "instanceof Integer " yang eksplisit dalam metode add() . Jika kami melakukannya, seluruh kelas kami hanya akan cocok untuk Integer , dan kami harus menulis kelas serupa untuk setiap tipe data lainnya di dunia! Kami akan mengandalkan pemrogram kami, dan tinggalkan komentar di kode untuk memastikan bahwa mereka tidak menambahkan apa pun yang tidak kami inginkan:

// Use this class ONLY with the Integer data type
public void add(Object o) {
   this.data[count] = o;
   count++;
}
Salah satu programmer melewatkan komentar ini dan secara tidak sengaja memasukkan beberapa String ke dalam daftar angka dan kemudian menghitung jumlahnya:

public class Main {

   public static void main(String[] args) {

       MyListClass list = new MyListClass();
       list.add(100);
       list.add(200);
       list.add("Lolkek");
       list.add("Shalala");

       Integer sum1 = (Integer) list.getData()[0] + (Integer) list.getData()[1];
       System.out.println(sum1);

       Integer sum2 = (Integer) list.getData()[2] + (Integer) list.getData()[3];
       System.out.println(sum2);
   }
}
Keluaran konsol:

300 
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
      at Main.main (Main.java:14)
Apa bagian terburuk dari situasi ini? Tentu bukan kecerobohan programmer. Bagian terburuknya adalah kode yang salah berakhir di tempat penting dalam program kami dan berhasil dikompilasi. Sekarang kita akan menemukan bug bukan saat menulis kode, tetapi hanya selama pengujian (dan ini adalah skenario kasus terbaik!). Memperbaiki bug pada tahap pengembangan selanjutnya membutuhkan biaya lebih banyak — baik dalam hal uang maupun waktu. Di sinilah manfaat generik bagi kita: kelas generik memungkinkan pemrogram yang tidak beruntung segera mendeteksi kesalahan. Program tidak dapat dikompilasi!

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

       List<Integer> myList1 = new ArrayList<>();
      
       myList1.add(100);
       myList1.add(100);
       myList1.add ("Lolkek"); // Error!
       myList1.add("Shalala"); // Error!
   }
}
Pemrogram segera menyadari kesalahannya dan langsung menjadi lebih baik. Omong-omong, kami tidak perlu membuat kelas Daftar kami sendiri untuk melihat kesalahan semacam ini. Cukup hapus tanda kurung sudut dan ketik ( <Integer> ) dari ArrayList biasa!

import java.util.ArrayList;
import java.util.List;

public class Main {

   public static void main(String[] args) {

      List list = new ArrayList();

      list.add(100);
      list.add(200);
      list.add("Lolkek");
      list.add("Shalala");

       System.out.println((Integer) list.get(0) + (Integer) list.get(1));
       System.out.println((Integer) list.get(2) + (Integer) list.get(3));
   }
}
Keluaran konsol:

300 
Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer 
     at Main.main(Main.java:16)
Dengan kata lain, bahkan dengan menggunakan mekanisme "asli" Java, kita dapat membuat kesalahan semacam ini dan membuat koleksi yang tidak aman. Namun, jika kami menempelkan kode ini ke dalam IDE, kami mendapat peringatan: "Panggilan yang tidak dicentang untuk menambahkan(E) sebagai anggota tipe mentah dari java.util.List" Kami diberi tahu bahwa mungkin ada yang salah saat menambahkan item ke koleksi yang tidak memiliki tipe generik. Tapi apa arti ungkapan "tipe mentah"? Tipe mentah adalah kelas generik yang tipenya telah dihapus. Dengan kata lain, List myList1 adalah tipe mentah . Kebalikan dari tipe mentah adalah tipe generik — kelas generik dengan indikasi tipe berparameter . Misalnya, List<String> myList1. Anda mungkin bertanya mengapa bahasa memungkinkan penggunaan tipe mentah ? Alasannya sederhana. Pencipta Java meninggalkan dukungan untuk tipe mentah dalam bahasa untuk menghindari masalah kompatibilitas. Pada saat Java 5.0 dirilis (generik pertama kali muncul di versi ini), banyak kode telah ditulis menggunakan tipe mentah . Hasilnya, mekanisme ini masih didukung hingga saat ini. Kami telah berulang kali menyebutkan buku klasik Joshua Bloch "Java Efektif" dalam pelajaran. Sebagai salah satu pencipta bahasa, dia tidak melewatkan tipe mentah dan tipe generik dalam bukunya. Apa itu obat generik di Jawa?  - 2Bab 23 buku ini memiliki judul yang sangat fasih: "Jangan gunakan tipe mentah dalam kode baru" Inilah yang perlu Anda ingat. Saat menggunakan kelas generik, jangan pernah mengubah tipe generik menjadi tipe mentah .

Metode generik

Java memungkinkan Anda membuat parameter metode individual dengan membuat apa yang disebut metode generik. Bagaimana metode seperti itu membantu? Yang terpenting, mereka sangat membantu karena memungkinkan Anda bekerja dengan berbagai jenis parameter metode. Jika logika yang sama dapat diterapkan dengan aman ke tipe yang berbeda, metode generik bisa menjadi solusi yang bagus. Pertimbangkan ini sebagai contoh yang sangat sederhana: Misalkan kita memiliki beberapa daftar bernama myList1 . Kami ingin menghapus semua nilai dari daftar dan mengisi semua ruang kosong dengan nilai baru. Inilah tampilan kelas kita dengan metode generik:

public class TestClass {

   public static <T> void fill(List<T> list, T val) {
       for (int i = 0; i < list.size(); i++)
           list.set(i, val);
   }

   public static void main(String[] args) {

       List<String> strings = new ArrayList<>();
       strings.add("Old String 1");
       strings.add("Old String 2");
       strings.add("Old String 3");

       fill(strings, "New String");

       System.out.println(strings);

       List<Integer> numbers = new ArrayList<>();
       numbers.add(1);
       numbers.add(2);
       numbers.add(3);

       fill(numbers, 888);
       System.out.println(numbers);
   }
}
Perhatikan sintaksnya. Ini terlihat agak tidak biasa:

public static <T> void fill(List<T> list, T val)
Kami menulis <T> sebelum tipe pengembalian. Ini menunjukkan bahwa kita sedang berhadapan dengan metode generik. Dalam hal ini, metode menerima 2 parameter sebagai input: daftar objek T dan objek T lain yang terpisah. Dengan menggunakan <T>, kami membuat parameter jenis parameter metode: kami tidak dapat meneruskan daftar String dan Integer. Daftar String dan String, daftar Integer dan Integer, daftar objek Cat kita sendiri dan objek Cat lainnya — itulah yang perlu kita lakukan. Metode main() mengilustrasikan bagaimana metode fill() dapat dengan mudah digunakan untuk bekerja dengan tipe data yang berbeda. Pertama, kami menggunakan metode dengan daftar String dan String sebagai input, dan kemudian dengan daftar Integer dan Integer. Keluaran konsol:

[New String, New String, New String] [888, 888, 888]
Bayangkan jika kita tidak memiliki metode generik dan membutuhkan logika metode fill() untuk 30 kelas yang berbeda. Kita harus menulis metode yang sama sebanyak 30 kali untuk tipe data yang berbeda! Namun berkat metode umum, kami dapat menggunakan kembali kode kami! :)

Kelas generik

Anda tidak terbatas pada kelas generik yang disediakan di perpustakaan Java standar — Anda dapat membuatnya sendiri! Berikut ini contoh sederhana:

public class Box<T> {

   private T t;

   public void set(T t) {
       this.t = t;
   }

   public T get() {
       return t;
   }

   public static void main(String[] args) {

       Box<String> stringBox = new Box<>();

       stringBox.set("Old String");
       System.out.println(stringBox.get());
       stringBox.set("New String");

       System.out.println(stringBox.get());
      
       stringBox.set(12345); // Compilation error!
   }
}
Kelas Box<T> kami adalah kelas generik. Setelah kami menetapkan tipe data ( <T> ) selama pembuatan, kami tidak lagi dapat menempatkan objek dari tipe lain di dalamnya. Ini bisa dilihat pada contoh. Saat membuat objek kami, kami menunjukkan bahwa itu akan berfungsi dengan Strings:

Box<String> stringBox = new Box<>();
Dan di baris kode terakhir, saat kami mencoba memasukkan angka 12345 ke dalam kotak, kami mendapatkan kesalahan kompilasi! Semudah itu! Kami telah membuat kelas generik kami sendiri! :) Dengan itu, pelajaran hari ini akan segera berakhir. Tapi kami tidak mengucapkan selamat tinggal pada obat generik! Dalam pelajaran berikutnya, kita akan membahas tentang fitur yang lebih canggih, jadi jangan pergi dulu! ) Untuk memperkuat apa yang Anda pelajari, kami sarankan Anda menonton video pelajaran dari Kursus Java kami
Semoga sukses dalam studi Anda! :)
Komentar
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION