Cơ bản về Phản ánh trong Java

Phản ánh (reflection) là kỹ thuật cho phép truy cập động vào lớp và đối tượng trong thời gian chạy. Đây là công nghệ được giới thiệu từ JDK 1.2, nền tảng cho nhiều tính năng động của các framework Java như cấu hình tham số, tiêm phụ thuộc.

Tải tĩnh: Lớp được tải trong quá trình biên dịch Tải động: Lớp được tải trong quá trình chạy chương trình

Phương thức Class.forName("tên lớp đầy đủ") cho phép tải lớp động, không yêu cầu tồn tại các tập tin class liên quan trong thời gian biên dịch.

Ví dụ minh họa

Xây dựng ứng dụng xử lý tài liệu với cấu trúc linh hoạt:

class DocumentHandler {
    public static void main(String[] args) {
        try {
            Class<?> clazz = Class.forName(args[0]);
            Application app = (Application) clazz.getDeclaredConstructor().newInstance();
            app.execute();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Giao diện chung cho các ứng dụng:

public interface Application {
    void execute();
}

Thực thi Word:

class WordProcessor implements Application {
    public void execute() {
        System.out.println("Khởi động Word");
    }
}

Thực thi Excel:

class Spreadsheet implements Application {
    public void execute() {
        System.out.println("Khởi động Excel");
    }
}

Chạy chương trình:

javac DocumentHandler.java
javac WordProcessor.java
java DocumentHandler WordProcessor
# Khởi động Word

Lớp Class và Tạo đối tượng động

Lớp Class trong JVM biểu diễn thông tin cấu trúc của lớp:

package com.example.reflect;

class Report {
    void generate() {
        System.out.println("Báo cáo được tạo");
    }
}

public class ClassExample {
    public static void main(String[] args) {
        // 3 cách lấy đối tượng Class
        Class<?> c1 = Report.class;
        Report report = new Report();
        Class<?> c2 = report.getClass();
        
        try {
            Class<?> c3 = Class.forName("com.example.reflect.Report");
            System.out.println(c1 == c2 && c2 == c3); // true
            
            // Tạo đối tượng từ Class
            Report obj = (Report) c1.getDeclaredConstructor().newInstance();
            obj.generate();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

Xử lý constructor, method và field

Constructor:

Class<?> employeeClass = Class.forName("com.example.model.Employee");
Constructor<?> constructor = employeeClass.getConstructor(
    Integer.class, String.class, Float.class, String.class
);
Employee emp = (Employee) constructor.newInstance(1001, "Trần Văn A", 5000f, "Kinh doanh");

Method:

Method updateMethod = employeeClass.getMethod("updateSalary", Float.class);
Employee updated = (Employee) updateMethod.invoke(emp, 1000f);

Field:

Field nameField = employeeClass.getField("name");
String name = (String) nameField.get(emp);
nameField.set(emp, "Nguyễn Thị B");

Truy cập toàn bộ field:

for (Field field : employeeClass.getDeclaredFields()) {
    if (field.isPublic()) {
        System.out.println(field.getName() + ": " + field.get(emp));
    } else {
        String getter = "get" + field.getName().substring(0,1).toUpperCase() + field.getName().substring(1);
        Method method = employeeClass.getMethod(getter);
        System.out.println(field.getName() + ": " + method.invoke(emp));
    }
}

Ứng dụng thực tế: Hệ thống đa ngôn ngữ (i18n) sử dụng phản ánh để điều chỉnh hành vi chương trình thông qua file cấu hình, tương tự cách Spring sử dụng applicationContext.xml để cấu hình lớp.

Thẻ: Java Reflection Class Loading Dynamic Instantiation Reflection API Interface Implementation

Đăng vào ngày 1 tháng 6 lúc 18:40