Bài viết được sự cho phép của tác giả Trần Hữu Cương
Java Reflection là gì?
Java Refelection là một tính năng (gọi là API hay thư viện cũng được) trong Java. Java Reflection cho phép truy cập các thông tin của đối tượng (tên class, các field, các method) và chỉnh sửa các field của đối tượng (kể cả các field private) trong quá trình run time.
Ta có thể áp dụng Java Reflection trong những trường hợp không biết object được xử lý là gì. (tên class là gì, ở package nào, có những field nào, method nào…).
Ví dụ mình muốn viết một hàm copy 2 đối tượng có thể dùng cho loại đối tượng khác nhau. Thì mình cần phải biết 2 đối tượng có cùng kiểu không, có những field nào, lấy và copy giá trị từng field.
Ngoài ra, với các field, method có modifier là private
thì ta không thể truy cập ở bên ngoài class đó. Trong những trường hợp bắt buộc phải gọi, truy cập các field, method private ở bên ngoài class đó thì Reflection là một giải pháp.
Tuyển dụng Java lương cao cho SV mới ra trường
Một số framework sử dụng Java Reflection:
- Spring
- JUnit
- Tomcat
- Eclipse (dùng để autocomplete)
- …
>>> Xem thêm: Thông não Java Design Pattern – Dependency Injection
Hạn chế, nhược điểm của Java Reflection
Trong trường hợp đã biết rõ cấu trúc class, có quyền truy cập các field, method thì ta không nên sử dụng Java Reflection bởi các lý do sau:
- Hiệu năng thấp: Ví dụ nó phải quét classpath để tìm class.
- Các vấn đề bảo mật: Việc chỉnh sửa class/object trong quá trình runtime có thể ảnh hưởng tới các thread … khiến cho ứng dụng bị fail.
- Khó bảo trì: Việc Reflection khá khó hiểu với người mới và không dễ để debug, nên sẽ rất khó để có thể tìm ra lỗi. Ngoài ra chúng ta cũng không thể check được một số lỗi trong quá trình compile (không tìm thấy class, không tìm thấy field…)
Các thành phần trong Java Reflection
Tương ứng với các thành phần trong một class, thì Java Reflection cũng cung cấp các class tương ứng để ta có thể xử lý:
- Class: Đại diện cho class/interface để lấy ra các thông tin của class (tên class, super class, class modifier, các method, các field …)
- Constructor: Xử lý các hàm khởi tạo của class
- Field: Xử lý các field của class (tên, modifier của field, lấy giá trị, thiết lập giá trị cho object…)
- Method: Xử lý các method của class (liệt kê các method, thực thi các method …)
>>> Xem thêm: Semaphore trong Java
Code ví dụ Java Reflection
Giả sử mình có 2 class sau:
Person.java
package stackjava.com.reflection; public class Person { public String address; // setter - getter }
Customer.java
package stackjava.com.reflection; public class Customer extends Person { private int age; protected String gender; public String name; String phone; public Customer() { } public Customer(int age, String name) { this.age = age; this.name = name; } // setter - getter @Override public String toString() { return "Customer [age=" + age + ", gender=" + gender + ", name=" + name + ", phone=" + phone + "]"; } }
Bây giờ mình sẽ thực hiện liệt kê tất cả các field, method của Class Customer:
package stackjava.com.reflection; import java.lang.reflect.*; public class Demo1 { public static void main(String[] args) throws ClassNotFoundException { Customer customer = new Customer(); customer.setName("kai"); customer.setAge(25); demoReflection(customer); } public static void demoReflection(Object object) throws ClassNotFoundException { Class myClass = object.getClass(); // Class myClass = Class.forName("stackjava.com.reflection.Customer"); System.out.println("Class name: " + myClass.getName()); System.out.println("Super Class name: " + myClass.getSuperclass().getName()); System.out.println("Is interface: " + myClass.isInterface()); System.out.println("Constructors: "); Constructor[] constructors = myClass.getDeclaredConstructors(); for (Constructor constructor : constructors) { System.out.println(" Number of parameters: " + constructor.getParameterCount() + " - modifier: " + getModifierName(constructor.getModifiers())); } System.out.println("Fields:"); Field[] allFields = myClass.getDeclaredFields(); for (Field field : allFields) { System.out.println(" " + field.getName() + " - type: " + field.getType() + " - modifier: " + getModifierName(field.getModifiers())); } System.out.println("Methods: "); Method[] methods = myClass.getDeclaredMethods(); for (Method field : methods) { System.out.println(" " + field.getName() + " - modifier: " + getModifierName(field.getModifiers())); } } public static String getModifierName(int mod) { if (Modifier.isPrivate(mod)) { return "private"; } if (Modifier.isProtected(mod)) { return "protected"; } if (Modifier.isPublic(mod)) { return "public"; } if (Modifier.isPrivate(mod)) { return "private"; } return "default"; } }
Bạn có thể lấy đối tượng Class thông qua một object với method getClass()
hoặc thông qua tên package + tên class với method Class.forName
Để lấy danh cách các hàm khởi tạo, các field, các method ta có thể dùng method getConstructors()
, getFields()
hoặc getMethods()
. Tuy nhiên các method không cho phép lấy các constructor, method, field có modifier là private do đó mình sẽ dùng getDeclaredConstructors()
, getDeclaredFields()
, getDeclaredMethods()
.
Method getModifier()
trả về modifier của class, method, field nhưng ở dạng số dó đó mình sẽ viết thêm method getModifierName để hiển thị nó dưới dạng String.
Để lấy giá trị hoặc truyền giá trị cho các field của đối tượng bạn có thể dùng method field.set()
/ field.get()
Demo:
Class name: stackjava.com.reflection.Customer Super Class name: stackjava.com.reflection.Person Is interface: false Constructors: Number of parameters: 0 - modifier: public Number of parameters: 2 - modifier: public Fields: age - type: int - modifier: private gender - type: class java.lang.String - modifier: protected name - type: class java.lang.String - modifier: public phone - type: class java.lang.String - modifier: default Methods: toString - modifier: public getName - modifier: public setName - modifier: public setAge - modifier: public hello - modifier: public setPhone - modifier: public goodbye - modifier: private setGender - modifier: public getPhone - modifier: public getAge - modifier: public getGender - modifier: public
Có thể bạn quan tâm:
- Java – ngôn ngữ không mới nhưng chưa bao giờ ngừng “hot”
- Java đang giãy chết?
- Nói về Serialization trong Java
Bài viết gốc được đăng tải tại stackjava.com
Xem thêm các việc làm Java hấp dẫn tại TopDev