Hướng dẫn và ví dụ Java Reflection

1- Java Reflection là gì ?

Java sử dụng từ “Java Reflection” để đặt tên cho một API quan trọng trong thư viện chuẩn của Java. Tại sao API này lại được đặt tên như vậy? Chúng hãy cùng phân tích ý nghĩa của việc này.

Reflection chính là một hình ảnh phản chiếu của một vật thể. Chẳng hạn hình ảnh của bạn trong một tấm gương, hoặc ảnh phản xạ của một cái cây trên mặt hồ. Từ “Java Reflection” đơn giản là đang ám chỉ một hình ảnh khác, một cách tiếp cận khác của Java.

Java là một ngôn ngữ hướng đối tượng (Object-oriented), thông thường bạn cần tạo ra một đối tượng và bạn có thể truy cập vào các trường (field), hoặc gọi phương thức (method) của đối tượng này thông qua toán tử dấu chấm (. )

Java Reflection giới thiệu một cách tiếp cận khác, bạn có thể truy cập vào một trường của một đối tượng nếu bạn biết tên của trường đó. Hoặc bạn có thể gọi một phương thức của đối tượng nếu bạn biết tên phương thức, các kiểu tham số của phương thức, và các giá trị tham số để truyền vào …

 

Java Reflecion cho phép bạn đánh giá, sửa đổi cấu trúc và hành vi của một đối tượng tại thời gian chạy (runtime) của chương trình. Đồng thời nó cho phép bạn truy cập vào các thành viên private (private member) tại mọi nơi trong ứng dụng, điều này không được phép với cách tiếp cận truyền thống.

  1. Java thông thường có thể được gọi là Java Introspection (Nội quan), chương trình có khả năng đánh giá cấu trúc của một đối tượng tại thời gian chạy (Runtime).
  2. Với Java Reflection, chương trình có khả năng đánh giá cấu trúc của một đối tượng tại thời gian chạy, sửa đổi cấu trúc và hành vi của đối tượng.

2- Một số class tham gia trong các ví dụ

Đây là 1 số ít class tham gia vào những ví dụ trong tài liệu này .

Animal. java


package org.o7planning.tutorial.beans;

public abstract class Animal {

   
   public String getLocation() {
       return "Earth";
   }
   
   public abstract int getNumberOfLegs() ;
   
}

Say. java


package org.o7planning.tutorial.beans;

public interface Say {
   
   public String say();
}

Cat. java


package org.o7planning.tutorial.beans;


public class Cat extends Animal implements Say {

   public static final String SAY = "Meo meo";
   public static final int NUMBER_OF_LEGS = 4;

   // Private field.
   private String name;
   
   // Private field
   public int age;

   public Cat() {

   }

   public Cat(String name) {
       this.name = name;
       this.age = 1;
   }

   public Cat(String name, int age) {
       this.name = name;
       this.age = age;
   }

   public String getName() {
       return this.name;
   }

   // Private Method.
   private void setName(String name) {
       this.name = name;
   }

   public int getAge() {
       return this.age;
   }

   public void setAge(int age) {
       this.age = age;
   }

   /**
    * Implements from interface Say.
    */
   @Override
   public String say() {
       return SAY;
   }

   /**
    * Implements from Animal.
    */
   @Override
   public int getNumberOfLegs() {
       return NUMBER_OF_LEGS;
   }

}

3- Bắt đầu với một ví dụ đơn giản

Đây là một ví dụ đơn thuần lấy ra list những method public của một class, gồm có cả những method thừa kế từ những class cha, và những interface .
ListMethod. java


package org.o7planning.tutorial.reflect.helloreflect;

import java.lang.reflect.Method;

public class ListMethod {

  // Protected method
  protected void info() {

  }

  public static void testMethod1() {

  }

  public void testMethod2() {

  }

  public static void main(String[] args) {

      // Lấy ra danh sách các method public của class này
      // Bao gồm các các method thừa kế từ class cha, hoặc các interface.
      Method[] methods = ListMethod.class.getMethods();

      for (Method method : methods) {
          System.out.println("Method " + method.getName());
      }

  }
}

Kết quả chạy class :


Method testMethod1
Method testMethod2
Method main
Method wait
Method wait
Method wait
Method equals
Method toString
Method hashCode
Method getClass
Method notify
Method notifyAll

4- Class

Một số method quan trọng trong Reflection liên quan tới Class.

Ví dụ ghi ra những thông tin cơ bản của class như tên class, package, modifier, ..
ShowClassInfo. java


package org.o7planning.tutorial.reflect.clazz;

import java.lang.reflect.Modifier;

public final class ShowClassInfo {

  public static void main(String[] args) {

      // Lấy ra đối tượng 'Class' mô tả class ShowClassInfo
      Class aClass = ShowClassInfo.class;

      // Ghi ra tên class, bao gồm cả tên package.
      System.out.println("Class Name= " + aClass.getName());

      // Ghi ra tên đơn giản của Class
      System.out.println("Simple Class Name= " + aClass.getSimpleName());

      // Thông tin Package.
      Package pkg = aClass.getPackage();
      System.out.println("Package Name = " + pkg.getName());

      // Modifier
      int modifiers = aClass.getModifiers();

      boolean isPublic = Modifier.isPublic(modifiers);
      boolean isInterface = Modifier.isInterface(modifiers);
      boolean isAbstract = Modifier.isAbstract(modifiers);
      boolean isFinal = Modifier.isFinal(modifiers);

      // true
      System.out.println("Is Public? " + isPublic);
      // true
      System.out.println("Is Final? " + isFinal);
      // false
      System.out.println("Is Interface? " + isInterface);
      // false
      System.out.println("Is Abstract? " + isAbstract);
  }

}

Kết quả chạy class


Class Name= org.o7planning.tutorial.reflect.clazz.ShowClassInfo
Simple Class Name= ShowClassInfo
Package Name = org.o7planning.tutorial.reflect.clazz
Is Public? true
Is Final? true
Is Interface? false
Is Abstract? false

Ví dụ ghi ra thông tin của class Cat, như tên class, và các Interface mà class này thi hành.

ShowClassCatInfo. java


package org.o7planning.tutorial.reflect.clazz;

import org.o7planning.tutorial.beans.Cat;

public class ShowClassCatInfo {

  public static void main(String[] args) {

      // Đối tượng Class mô tả class Cat.
      Class aClass = Cat.class;

      // Tên class
      System.out.println("Simple Class Name = " + aClass.getSimpleName());

      // Lấy ra đối tượng class mô tả class cha của class Cat.
      Class aSuperClass = aClass.getSuperclass();

      System.out.println("Simple Class Name of Super class = "
              + aSuperClass.getSimpleName());

      // Lấy ra mảng các Class mô tả các Interface mà Cat thi hành.
      Class[] itfClasses = aClass.getInterfaces();

      for (Class itfClass : itfClasses) {
          System.out.println("Interface: " + itfClass.getSimpleName());
      }

  }
}

Kết quả chạy class :


Simple Class Name = Cat
Simple Class Name of Super class = Animal
Interface: Say

Ví dụ lấy ra thông tin những constructor, method, field của class ( Chỉ public ), gồm có cả những public method, public field, thừa kế từ những class cha, và những interace .
ShowMemberInfo. java


package org.o7planning.tutorial.reflect.clazz;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.o7planning.tutorial.beans.Cat;

public class ShowMemberInfo {

  public static void main(String[] args) {

      // Lấy ra đối tượng Class mô tả class Cat
      Class aClass = Cat.class;

      // Lấy ra danh sách các cấu tử của Cat.
      Constructor[] constructors = aClass.getConstructors();

      System.out.println(" ==== CONSTRUCTORs:  ===== ");

      for (Constructor constructor : constructors) {
          System.out.println("Constructor: " + constructor.getName());
      }

      // Lấy ra danh sách các method public của Cat
      // Bao gồm cả các method thừa kế từ class cha và các interface
      Method[] methods = aClass.getMethods();

      System.out.println(" ==== METHODs:   ====== ");
      for (Method method : methods) {
          System.out.println("Method: " + method.getName());
      }

      // Lấy ra danh sách các field public
      // Kể các các public field thừa kế từ các class cha, và các interface
      Field[] fields = aClass.getFields();

      System.out.println(" ==== FIELDs:    ====== ");
      for (Field field : fields) {
          System.out.println("Field: " + field.getName());
      }

  }
}

Kết quả


 ==== CONSTRUCTORs:  =====
Constructor: org.o7planning.tutorial.beans.Cat
Constructor: org.o7planning.tutorial.beans.Cat
Constructor: org.o7planning.tutorial.beans.Cat
 ==== METHODs:   ======
Method: getAge
Method: setAge
Method: say
Method: getNumberOfLegs
Method: getName
Method: getLocation
Method: wait
Method: wait
Method: wait
Method: equals
Method: toString
Method: hashCode
Method: getClass
Method: notify
Method: notifyAll
 ==== FIELDs:    ======
Field: SAY
Field: NUMBER_OF_LEGS
Field: age

5- Cấu tử (Constructor)

Ví dụ lấy ra một cấu tử với ( constructor ) những tham số chỉ định trước. Và ghi ra thông tin về cấu tử ( constructor ) này .
ConstructorExample. java


package org.o7planning.tutorial.reflect.constructor;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.o7planning.tutorial.beans.Cat;

public class ConstructorExample {

  public static void main(String[] args) throws NoSuchMethodException,
          SecurityException, InstantiationException, IllegalAccessException,
          IllegalArgumentException, InvocationTargetException {

      // Lấy ra đối tượng Class mô tả class Cat
      Class aClass = Cat.class;

      // Lấy ra cấu tử có tham số (String,int) của class Cat

      Constructor constructor = aClass.getConstructor(String.class,
              int.class);

      // Lấy ra thông tin kiểu tham số của cấu tử.
      Class[] paramClasses = constructor.getParameterTypes();

      for (Class paramClass : paramClasses) {
          System.out.println("Param: " + paramClass.getSimpleName());
      }

      // Khởi tạo đối tượng Cat theo cách thông thường.
      Cat tom = new Cat("Tom", 3);
      System.out
              .println("Cat 1: " + tom.getName() + ", age =" + tom.getAge());

      // Khởi tạo đối tượng Cat theo cách của reflect.
      Cat tom2 = (Cat) constructor.newInstance("Tom", 2);
      System.out.println("Cat 2: " + tom.getName() + ", age ="
              + tom2.getAge());
  }
}

Kết quả chạy class :


Param: String
Param: int
Cat 1: Tom, age =3
Cat 2: Tom, age =2

6- Trường (Field)

Ví dụ dưới đây lấy ra field với tên chỉ định sẵn.

FieldExample. java


package org.o7planning.tutorial.reflect.field;

import java.lang.reflect.Field;

import org.o7planning.tutorial.beans.Cat;

public class FieldExample {

  public static void main(String[] args) throws NoSuchFieldException,
          SecurityException, IllegalArgumentException, IllegalAccessException {
     
      // Lấy ra đối tượng Class mô tả class Cat
      Class aClass = Cat.class;

      // Lấy ra field có tên 'NUMBER_OF_LEGS':
      Field field = aClass.getField("NUMBER_OF_LEGS");

      // Ghi ra kiểu của Field
      Class fieldType = field.getType();

      System.out.println("Field type: " + fieldType.getSimpleName());

      Field ageField = aClass.getField("age");

      Cat tom = new Cat("Tom", 5);

      // Lấy ra giá trị của trường "age" theo cách của Reflect.
      Integer age = (Integer) ageField.get(tom);
      System.out.println("Age = " + age);
     
      // Sét đặt giá trị mới cho trường "age".
      ageField.set(tom, 7);
     
      System.out.println("New Age = "+ tom.getAge());
     

  }

}

Kết quả chạy class :


Field type: int
Age = 5
New Age = 7

7- Phương thức (method)

Ví dụ lấy ra một method cho bởi tên, và những tham số chỉ định trước. Ghi ra thông tin về method này, như kiểu trả về, list những tham số, …
MethodExample. java


package org.o7planning.tutorial.reflect.method;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.o7planning.tutorial.beans.Cat;

public class MethodExample {

  public static void main(String[] args) throws NoSuchMethodException,
          SecurityException, IllegalAccessException,
          IllegalArgumentException, InvocationTargetException {

      // Lấy ra đối tượng Class mô tả class Cat
      Class aClass = Cat.class;

      // Lấy ra đối tượng 'Method' mô tả method getAge()
      Method getAgeMethod = aClass.getMethod("getAge");
     
      // Kiểu trả về của method getAge
      Class returnType= getAgeMethod.getReturnType();
      System.out.println("Return type of getAge: "+ returnType.getSimpleName());
     

      Cat tom = new Cat("Tom", 7);

      // Gọi method 'getAge' theo cách của Reflect
      // Nó tương đương với gọi: tom.getAge()
      int age = (int) getAgeMethod.invoke(tom);

      System.out.println("Age = " + age);

      // Lấy ra đối tượng 'Method' mô tả method setAge(int) của class Cat.
      Method setAgeMethod = aClass.getMethod("setAge", int.class);

      // Gọi method setAge(int) theo cách của Reflect.
      // Nó tương đương với gọi: tom.setAge(5);
      setAgeMethod.invoke(tom, 5);
     
      System.out.println("New Age = " + tom.getAge());
  }
}

Kết quả chạy class


Return type of getAge: int
Age = 7
New Age = 5

8- Các phương thức getter và setter

Ví dụ dưới đây, liệt kê ra các phương thức public setter, và các public getter của class.

GetSetExample. java


package org.o7planning.tutorial.reflect.getset;

import java.lang.reflect.Method;

import org.o7planning.tutorial.beans.Cat;

public class GetSetExample {

   // Method là getter nếu có tên bắt đầu bằng get, và không có tham số.
   public static boolean isGetter(Method method) {
       if (!method.getName().startsWith("get")) {
           return false;
       }
       if (method.getParameterTypes().length != 0) {
           return false;
       }
       if (void.class.equals(method.getReturnType())) {
           return false;
       }
       return true;
   }

   
   // Method là setter nếu có tên bắt đầu bằng set, và chỉ có 1 tham số.    
   public static boolean isSetter(Method method) {
       if (!method.getName().startsWith("set")) {
           return false;
       }
       if (method.getParameterTypes().length != 1) {
           return false;
       }
       return true;
   }

   public static void main(String[] args) {

       // Lấy ra đối tượng Class mô tả class Cat
       Class aClass = Cat.class;

       // Lấy ra danh sách các public method.
       Method[] methods = aClass.getMethods();

       for (Method method : methods) {
           boolean isSetter = isSetter(method);
           boolean isGetter = isGetter(method);
           System.out.println("Method: " + method.getName());
           System.out.println(" - Is Setter? " + isSetter);
           System.out.println(" - Is Getter? " + isGetter);
       }

   }
   
}

Kết quả chạy chương trình :


Method: getName
- Is Setter? false
- Is Getter? true
Method: getNumberOfLegs
- Is Setter? false
- Is Getter? true
Method: getAge
- Is Setter? false
- Is Getter? true
Method: setAge
- Is Setter? true
- Is Getter? false
Method: say
- Is Setter? false
- Is Getter? false
Method: getLocation
- Is Setter? false
- Is Getter? true
Method: wait
- Is Setter? false
- Is Getter? false
Method: wait
- Is Setter? false
- Is Getter? false
Method: wait
- Is Setter? false
- Is Getter? false
Method: equals
- Is Setter? false
- Is Getter? false
Method: toString
- Is Setter? false
- Is Getter? false
Method: hashCode
- Is Setter? false
- Is Getter? false
Method: getClass
- Is Setter? false
- Is Getter? true
Method: notify
- Is Setter? false
- Is Getter? false
Method: notifyAll
- Is Setter? false
- Is Getter? false

9- Truy cập vào các private method, field

Bạn không thể truy cập vào các method hay field mà nó là private theo cách thông thường, quá trình biên dịch java cũng không cho phép điều đó. Nhưng với Java Reflection điều đó hoàn toàn có thể.

AccessPrivateFieldExample. java


package org.o7planning.tutorial.reflect.privateaccess;

import java.lang.reflect.Field;

import org.o7planning.tutorial.beans.Cat;

public class AccessPrivateFieldExample {

    public static void main(String[] args) throws IllegalArgumentException,
            IllegalAccessException, NoSuchFieldException, SecurityException {

        // Tạo một đối tượng Class mô tả class Cat.
        Class aClass = Cat.class;

        // Class.getField(String) chỉ lấy được các trường public.
        // Sử dụng Class.getDeclaredField(String):
        // Lấy ra đối tượng Field mô tả trường name của class Cat.
        // (Trường khi báo trong class này).
        Field private_nameField = aClass.getDeclaredField("name");

        // Cho phép để truy cập vào các trường private.
        // Nếu không sẽ bị ngoại lệ IllegalAccessException
        private_nameField.setAccessible(true);

        Cat tom = new Cat("Tom");

        String fieldValue = (String) private_nameField.get(tom);
        System.out.println("Value field name = " + fieldValue);

        // Sét đặt trường name giá trị mới.
        private_nameField.set(tom, "Tom Cat");

        System.out.println("New name = " + tom.getName());
    }

}

Kết quả chạy class :


Value field name = Tom
New name = Tom Cat

Tiếp theo ví dụ truy vấn vào một private method .
AccessPrivateMethodExample. java


package org.o7planning.tutorial.reflect.privateaccess;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import org.o7planning.tutorial.beans.Cat;

public class AccessPrivateMethodExample {

    public static void main(String[] args) throws NoSuchMethodException,
            SecurityException, IllegalAccessException,
            IllegalArgumentException, InvocationTargetException {

        // Tạo một đối tượng Class mô tả class Cat.
        Class aClass = Cat.class;

        // Class.getMethod(String) chỉ lấy được các method public.
        // Sử dụng Class.getDeclaredMethod(String):
        // Lấy ra đối tượng Method mô tả method setName(String) của class Cat.
        // (Phương thức khai báo trong class).
        Method private_setNameMethod = aClass.getDeclaredMethod("setName",
                String.class);

        // Cho phép để truy cập vào các method private.
        // Nếu không sẽ bị ngoại lệ IllegalAccessException
        private_setNameMethod.setAccessible(true);

        Cat tom = new Cat("Tom");

        // Gọi private method.
        private_setNameMethod.invoke(tom, "Tom Cat");

        System.out.println("New name = " + tom.getName());
    }
    

}

Kết quả


New name = Tom Cat

10- Annotation


MyAnnotation. java


package org.o7planning.tutorial.reflect.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

// Annotation này có thể sử dụng tại thời điểm chạy (Runtime) của chương trình.
@Retention(RetentionPolicy.RUNTIME)
// Có thể dùng cho class,interface, method, field, parameter.
@Target({ ElementType.TYPE, ElementType.METHOD, ElementType.FIELD,
       ElementType.PARAMETER })
public @interface MyAnnotation {

   String name();

   String value() default "";
}

Một ví dụ Annotation với class :
ClassAnnotationExample. java


package org.o7planning.tutorial.reflect.annotation;

import java.lang.annotation.Annotation;

@MyAnnotation(name = "Table", value = "Employee")
public class ClassAnnotationExample {

   public static void main(String[] args) {

       Class aClass = ClassAnnotationExample.class;

       // Lấy ra danh sách các Annotation của class.
       Annotation[] annotations = aClass.getAnnotations();

       for (Annotation ann : annotations) {
           System.out.println("Annotation: " + ann.annotationType().getSimpleName());
       }

       // Hoặc lấy cụ thể.
       Annotation ann = aClass.getAnnotation(MyAnnotation.class);
       MyAnnotation myAnn = (MyAnnotation) ann;
       System.out.println("Name = " + myAnn.name());
       System.out.println("Value = " + myAnn.value());
   }
}

Kết quả :


Annotation: MyAnnotation
Name = Table
Value = Employee

Một ví dụ Annotation với Field và Method :

FieldMethodAnnotationExample.java


package org.o7planning.tutorial.reflect.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

public class FieldMethodAnnotationExample {

   @MyAnnotation(name = "My Field")
   private int myField;

   @MyAnnotation(name = "My Method", value = "My Method Value")
   protected void myMethod(String str) {

   }

   public static void main(String[] args) throws NoSuchFieldException,
           SecurityException, NoSuchMethodException {

       Class aClass = FieldMethodAnnotationExample.class;

       //
       System.out.println(" == FIELD == ");
       Field field = aClass.getDeclaredField("myField");

       // Lấy ra danh sách các Annotation của field.
       Annotation[] fieldAnns = field.getAnnotations();

       for (Annotation methodAnn : fieldAnns) {
           System.out.println("Annotation: "
                   + methodAnn.annotationType().getSimpleName());
       }
       // Lấy cụ thể.
       Annotation fieldAnn = field.getAnnotation(MyAnnotation.class);

       MyAnnotation myAnn1 = (MyAnnotation) fieldAnn;

       System.out.println("Name = " + myAnn1.name());
       System.out.println("Value = " + myAnn1.value());

       // Tương tự với method ...
       System.out.println(" == METHOD == ");

       Method method = aClass.getDeclaredMethod("myMethod", String.class);

       // Lấy ra danh sách các Annotation của method.
       Annotation[] methodAnns = method.getAnnotations();

       for (Annotation methodAnn : methodAnns) {
           System.out.println("Annotation: "
                   + methodAnn.annotationType().getSimpleName());
       }

       // Lấy cụ thể.
       Annotation methodAnn = method.getAnnotation(MyAnnotation.class);
       MyAnnotation myAnn2 = (MyAnnotation) methodAnn;

       System.out.println("Name = " + myAnn2.name());
       System.out.println("Value = " + myAnn2.value());

   }
}

Kết quả chạy :


 == FIELD ==
Annotation: MyAnnotation
Name = My Field
Value =
 == METHOD ==
Annotation: MyAnnotation
Name = My Method
Value = My Method Value

Ví dụ Annotation với tham số của method:

ParameterAnnotationExample. java


package org.o7planning.tutorial.reflect.annotation;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;

public class ParameterAnnotationExample {

   // Ví dụ một method có Annotation ở tham số.
   protected void doSomething(int jobType,
           @MyAnnotation(name = "Table", value = "Employee") String info) {

   }

   public static void main(String[] args) throws NoSuchMethodException,
           SecurityException {

       Class aClass = ParameterAnnotationExample.class;

       // Lấy ra đối tượng Method của method doSomething(int,String)
       Method method = aClass.getDeclaredMethod("doSomething", int.class,
               String.class);

       // Lấy ra danh sách các Parameter của method.
       Class[] parameterTypes = method.getParameterTypes();
       for (Class parameterType : parameterTypes) {
           System.out.println("Parametete Type: "
                   + parameterType.getSimpleName());
       }

       System.out.println(" ---- ");
       
       // Lấy ra mảng 2 chiều các Annotation trong các Parameter.
       Annotation[][] annotationss = method.getParameterAnnotations();

       // Lấy ra danh sách các Annotation của Parameter tại vị trí Index =1.
       Annotation[] annotations = annotationss[1];

       for (Annotation ann : annotations) {
           System.out.println("Annotation: "
                   + ann.annotationType().getSimpleName());
       }
   }
}

Parametete Type: int
Parametete Type: String
 ----
Annotation: MyAnnotation