Java Reflection là gì? Hướng dẫn Java Reflection API

9591

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:

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