Lấy Tên Lớp Và Phương Thức Đang Thực Thi Trong Java

Trong quá trình phát triển ứng dụng Java, việc thu thập thông tin động về môi trường thực thi giúp ích rất lớn cho việc thiết lập hệ thống log, debug hoặc xây dựng các framework kiểm thử. Hai phương pháp chính thường được sử dụng để truy xuất tên lớp và tên phương thức đang chạy bao gồm việc dựa trên đối tượng hiện tại và phân tích ngăn xếp thực thi.

Sử dụng Phép Toán Trên Đối Tượng

Mỗi đối tượng trong Java đều thừa hưởng phương thức getClass() từ lớp Object. Đây là cách đơn giản nhất để lấy ra lớp runtime của chính đối tượng đó. Tuy nhiên, phương pháp này chỉ khả dụng khi bạn nằm trong thân của một instance method (phương thức thuộc thể hiện).

Cú pháp cơ bản như sau:

String className = this.getClass().getSimpleName();

Những lưu ý quan trọng khi áp dụng cách này:

  • Không dùng được trong static: Biến this sẽ không tồn tại nếu mã lệnh nằm trong phương thức tĩnh.
  • Vấn đề đa hình: Nếu lớp con ghi đè (override) phương thức từ lớp cha, getClass() sẽ trả về loại thực tế của đối tượng mới hơn là lớp nơi định nghĩa phương thức.

Sử Dụng Ngăn Sắp Thực Thi (Stack Trace)

Đối với các phương thức tĩnh hoặc khi cần lấy thông tin của người gọi, việc truy cập vào Thread thông qua ngăn xếp thực thi (stack trace) là giải pháp hiệu quả hơn. Hàm Thread.currentThread().getStackTrace() trả về một mảng chứa các khung gọi (frames).

Mảng trả về có cấu trúc đặc thù:

  1. Phần tử thứ 0 (Index 0): Chính là phương thức getStackTrace().
  2. Phần tử thứ 1 (Index 1): Là phương thức đang thực thi mã lệnh gọi hàm trên.

Từ vị trí Index 1 này, ta có thể tách biệt tên lớp và tên phương thức bằng các getter tương ứng.

// Lấy tên lớp
String className = Thread.currentThread().getStackTrace()[1].getClassName();

// Lấy tên phương thức
String methodName = Thread.currentThread().getStackTrace()[1].getMethodName();

Thực Hành Triển Khai

Dưới đây là ví dụ minh họa chi tiết kết hợp cả hai phương pháp trên trong một lớp tiện ích. Mã nguồn này bao gồm một phương thức tĩnh và một phương thức thường để kiểm chứng sự khác biệt.

package com.example.utility;
import java.lang.reflect.Method;
public class RuntimeIntrospector {
    public static void main(String[] args) {
        // Gọi thử từ static context
        analyzeStaticContext();
    }
    /**
     * Truy xuất thông tin trong phương thức tĩnh
     */
    private static void analyzeStaticContext() {
        int index = 1;
        StackTraceElement element = Thread.currentThread()
            .getStackTrace()[index];
 
        String callerClass = element.getClassName();
        String callerFunc = element.getMethodName();
 
        System.out.printf("[Static] Class: %s | Func: %s%n", callerClass, callerFunc);
    }
 
    /**
     * Truy xuất thông tin trong phương thức instance
     */
    public void analyzeInstanceContext() {
        // Cách 1: Dựa trên đối tượng hiện tại
        String runtimeClassName = this.getClass().getName();
 
        // Cách 2: Dựa trên Stack Trace
        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
        String stackClassName = trace[1].getClassName();
        String stackMethodName = trace[1].getMethodName();
 
        System.out.printf("[Instance] ObjType: %s%n", runtimeClassName);
        System.out.printf("[Stack]   CallerClass: %s | CallerFunc: %s%n", stackClassName, stackMethodName);
    }
}

Kết Luận Kỹ Thuật

Việc chọn phương pháp nào phụ thuộc vào mục đích cụ thể của bạn. Nếu muốn biết chính xác loại thực thi của đối tượng, hãy dùng getClass(). Ngược lại, nếu cần log lại đường đi điều khiển hoặc biết ai gọi hàm hiện tại, thì phân tích StackTrace là lựa chọn tối ưu.

Thẻ: Java Reflection stacktrace debugging runtime-introspection

Đăng vào ngày 4 tháng 7 lúc 01:59