openplanning

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

  1. Java Reflection là gì ?
  2. Một số class tham gia trong các ví dụ
  3. Bắt đầu với một ví dụ đơn giản
  4. Class
  5. Cấu tử (Constructor)
  6. Trường (Field)
  7. Phương thức (method)
  8. Các phương thức getter và setter
  9. Truy cập vào các private method, field
  10. Annotation

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.
  • 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).
  • 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à một số class tham gia vào các 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 giản lấy ra danh sách các method public của một class, bao gồm cả các method thừa kế từ các class cha, và các 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 các 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<ShowClassInfo> 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<Cat> 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 các constructor, method, field của class (Chỉ public), bao gồm cả các public method, public field, thừa kế từ các class cha, và các 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<Cat> 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) các 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<Cat> 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<Cat> 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à các tham số chỉ định trước. Ghi ra thông tin về method này, như kiểu trả về, danh sách các 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<Cat> 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<Cat> 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<Cat> 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 cập 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<Cat> 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 & 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

Java cơ bản

Show More