![translation](https://cdn.durumis.com/common/trans.png)
Ini adalah postingan yang diterjemahkan oleh AI.
Pilih Bahasa
Teks yang dirangkum oleh AI durumis
- Refleksi adalah API yang memungkinkan Anda untuk mengakses informasi kelas dan memanipulasi kelas sesuai keinginan Anda pada saat runtime.
- Melalui refleksi, Anda dapat membuat instance kelas dan mengakses bidang dan metode tanpa memperhatikan pengubah akses, dan khususnya berguna dalam mengelola ketergantungan secara dinamis selama pengembangan skala besar, seperti kerangka kerja.
- Namun, hal ini dapat melanggar enkapsulasi dan menyebabkan penurunan kinerja, jadi sebaiknya hanya digunakan jika diperlukan.
Apa itu Reflection?
Refleksi adalah API yang mendukung untuk membuat instance kelas yang diinginkan melalui objek tipe Class yang dimuat di area heap, dan mendukung untuk mengakses field dan method dari instance terlepas dari pengontrol akses.
Di sini, yang dimaksud dengan kelas yang dimuat adalah setelah class loader JVM menyelesaikan pemuatan file kelas,objek tipe Classdibuat yang menyimpan informasi tentang kelas tersebut dan disimpan di area heap memori. Perhatikan bahwa ini berbeda dari objek yang dibuat menggunakan kata kunci new. Jika Anda tidak memahami objek tipe Class ini, Anda dapat memeriksa dokumentasi JDK untuk objek java.lang.class.
Cara Penggunaan
Sebelum menggunakan refleksi, Anda perlu mengambil objek tipe Class yang dimuat di area heap. Ada 3 cara.
- Ambil dengan kelas.class
- Ambil dengan instance.getClass()
- Ambil dengan Class.forName("nama kelas")
public class Member {
private String name;
protected int age;
public String hobby;
public Member() {
}
public Member(String name, int age, String hobby) {
this.name = name;
this.age = age;
this.hobby = hobby;
}
public void speak(String message) {
System.out.println(message);
}
private void secret() {
System.out.println("Kata sandi adalah 1234.");
}
@Override
public String toString() {
return "Member{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
public class Main {
public static void main(String[] args) throws ClassNotFoundException {
Class memberClass = Member.class;
System.out.println(System.identityHashCode(memberClass));
Member member = new Member("Jayon", 23, "Pengembang Darats");
Class extends Member> memberClass2 = member.getClass();
System.out.println(System.identityHashCode(memberClass2));
Class> memberClass3 = Class.forName("{nama paket}.Member");
System.out.println(System.identityHashCode(memberClass3));
}
}
// Hasil eksekusi
1740000325
1740000325
Anda dapat melihat bahwa ketiga cara untuk mengambil instance tipe Class semuanya sama. Tidak peduli metode mana yang Anda gunakan, nilai hashnya sama, jadi Anda dapat menggunakannya dengan tepat sesuai kebutuhan.
Sekarang, melalui tipe Class yang Anda ambil, Anda dapat membuat instance dari kelas tersebut, dan Anda dapat mengakses field dan method dari instance terlepas dari pengontrol akses. Pertama, mari kita buat instance dari kelas tersebut.
public class Main {
public static void main(String[] args) throws Exception {
// Cetak semua konstruktor Member
Member member = new Member();
Class extends Member> memberClass = member.getClass();
Arrays.stream(memberClass.getConstructors()).forEach(System.out::println);
// Membuat instance melalui konstruktor default Member
Constructor extends Member> constructor = memberClass.getConstructor();
Member member2 = constructor.newInstance();
System.out.println("member2 = " + member2);
// Membuat instance melalui konstruktor lain dari Member
Constructor extends Member> fullConstructor =
memberClass.getConstructor(String.class, int.class, String.class);
Member member3 = fullConstructor.newInstance("Jayon", 23, "Pengembang Darats");
System.out.println("member3 = " + member3);
}
}
// Hasil eksekusi
public Member()
public Member(java.lang.String,int,java.lang.String)
member2 = Member{name='null', age=0, hobby='null'}
Anda dapat memperoleh konstruktor melalui getConstructor() dan membuat instance Member secara dinamis melalui newInstance().
Terakhir, mari kita coba mengakses field dan method dari instance terlepas dari pengontrol akses.
public class Main {
public static void main(String[] args) throws Exception {
Member member = new Member("Jayon", 23, "Pengembang Darats");
Class extends Member> memberClass = member.getClass();
// Mengakses field
Field[] fields = memberClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true);
System.out.println(field.get(member));
}
fields[0].set(member, "Jayon2");
System.out.println(member);
// Mengakses method
Method speakMethod = memberClass.getDeclaredMethod("speak", String.class);
speakMethod.invoke(member, "Pengujian refleksi");
Method secretMethod = memberClass.getDeclaredMethod("secret");
secretMethod.setAccessible(true);
secretMethod.invoke(member);
}
}
// Hasil eksekusi
Jayon
23
Pengembang Darats
Member{name='Jayon2', age=23, hobby='Pengembang Darats'}
Pengujian refleksi
Anda dapat melihat bahwa Anda dapat memperoleh semua variabel instance kelas melalui getDeclaredFileds(), mengembalikan nilai field melalui get(), dan memodifikasi nilai field melalui set(). Poin yang perlu diperhatikan di sini adalah ketika mengakses field yang memiliki pengontrol akses private, Anda harus mengirimkan true ke setAccessible() sebagai argumen.
Method juga dapat diperoleh melalui getDeclaredMethod(). Pada saat itu, Anda perlu mengirimkan nama method dan tipe parameter sebagai argumen. Demikian pula, Anda perlu menetapkan argumen setAccessible() ke true ketika mengakses method yang memiliki pengontrol akses private. Terakhir, Anda dapat memanggil method yang diperoleh melalui API refleksi melalui method invoke().
Kelebihan dan Kekurangan
- Kelebihan
- Ini memiliki fleksibilitas untuk membuat instance kelas pada saat runtime, mengakses field dan method tanpa memperhatikan pengontrol akses, dan melakukan tugas yang diperlukan.
- Kekurangan
- Melemahkan enkapsulasi.
- Karena instance dibuat pada saat runtime, tipe tersebut tidak dapat diperiksa pada saat compile time.
- Karena instance dibuat pada saat runtime, sulit untuk memahami alur kerja khusus.
- Performa lebih lambat daripada mengakses field dan method menggunakan refleksi. (Tidak semua situasi lebih lambat.)
Alasan Penggunaan
Melalui API refleksi, Anda dapat mengakses informasi kelas pada saat runtime dan memanipulasi kelas sesuai keinginan. Bahkan field dan method yang dideklarasikan dengan pengontrol akses private dapat dimanipulasi. Ini tampak seperti teknologi yang tidak boleh digunakan karena merusak enkapsulasi dalam desain berorientasi objek.
Pada tahap konsol berukuran kecil, pengembang dapat memahami semua objek dan ketergantungan yang akan digunakan dalam program pada saat compile time. Namun, pada tahap pengembangan skala besar seperti kerangka kerja, sulit untuk memahami banyak objek dan ketergantungan. Pada saat ini, refleksi dapat digunakan untuk membuat kelas secara dinamis dan membangun ketergantungan.
Misalnya, dalam Bean Factory Spring, Anda dapat melihat bahwa Bean Factory secara otomatis membuat dan mengelola kelas yang memiliki anotasi seperti @Controller, @Service, dan @Repository, hanya dengan melampirkan anotasi tersebut. Pengembang tidak pernah memberi tahu Bean Factory tentang kelas tersebut, tetapi ini dimungkinkan karena refleksi. Jika Anda menemukan kelas yang memiliki anotasi tersebut pada saat runtime, refleksi digunakan untuk membuat instance kelas tersebut, menyuntikkan field yang diperlukan, dan menyimpannya di Bean Factory.
Tentu saja, seperti yang disebutkan di atas, karena merusak enkapsulasi, yang terbaik adalah menggunakannya hanya jika diperlukan.