GP Coder

Trang chia sẻ kiến thức lập trình Java

  • Java Core
    • Basic Java
    • OOP
    • Exception Handling
    • Multi-Thread
    • Java I/O
    • Networking
    • Reflection
    • Collection
    • Java 8
  • Design pattern
    • Creational Pattern
    • Structuaral Pattern
    • Behavior Pattern
  • Web Service
    • SOAP
    • REST
  • JPA
  • Java library
    • Report
    • Json
    • Unit Test
  • Message Queue
    • ActiveMQ
    • RabbitMQ
  • All
Trang chủ Java Core Reflection Hướng dẫn sử dụng Java Reflection

Hướng dẫn sử dụng Java Reflection

Đăng vào 03/12/2017 . Được đăng bởi GP Coder . 30254 Lượt xem . Toàn màn hình

Nội dung

  • 1 Java Reflection là gì?
  • 2 Một số class được sử dụng trong bài viết này
  • 3 Kiến trúc của Java Reflection API

Java Reflection là gì?

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 truy cập, 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 Reflection khá mạnh mẽ và rất hữu ích đối với những ai hiểu rõ về nó. Ví dụ, bạn có thể ánh xạ (mapping) đối tượng (object) thành table dưới database tại thời điểm runtime. Kỹ thuật này các bạn có thể thấy rõ nhất ở JPA và Hibernate.

Một số class được sử dụng trong bài viết này

Animal.java


package com.gpcoder.reflection;

public abstract class Animal {

	public String getLocation() {
		return "VietNam";
	}

	public abstract int getNumberOfLegs();

}

Say.java


package com.gpcoder.reflection;

public interface Say {

	public String say();

}

Cat.java


package com.gpcoder.reflection;

@Excel(name = "Cat")
public class Cat extends Animal implements Say {

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

	// Private fields
	@ExcelColumn(index = 0, title = "Name")
	private String name;

	@ExcelColumn(index = 1, title = "Age")
	public int age;

	// Construnctors
	public Cat() {

	}

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

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

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

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

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

	// Getters and setters

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

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

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

}

Excel.java


package com.gpcoder.reflection;

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

@Documented
@Target(ElementType.TYPE)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface Excel {

	int index() default 0;

	String name() default "Sheet 1";

}

ExcelColumn.java


package com.gpcoder.reflection;

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

@Documented
@Target(ElementType.FIELD)
@Inherited
@Retention(RetentionPolicy.RUNTIME)
public @interface ExcelColumn {

	int index();

	String title();

	String description() default "Default value";

}

Kiến trúc của Java Reflection API

Các lớp được dùng trong reflection nằm trong hai package là java.lang và java.lang.reflect. Package java.lang.reflect bao gồm ba lớp chính mà bạn cần biết là Constructor, Field và Method:

  • Class<T>: lớp này đại diện cho các lớp, interface và chứa các phương thức dùng để lấy các đối tượng kiểu Constructor, Field, Method,…
  • AccessibleObject: các kiểm tra về phạm vi truy xuất (public, private, protected) của field, method, constructor sẽ được bỏ qua. Nhờ đó bạn có thể dùng reflection để thay đổi, thực thi các thành phần này mà không cần quan tâm đến phạm vi truy xuất của nó.
  • Constructor: chứa các thông tin về một constructor của lớp.
  • Field: chứa các thông tin về một field của lớp, interface.
  • Method: chứa các thông tin về một phương thức của lớp, interface.

Lớp (Classes)

Khi sử dụng Java Reflection để duyệt qua một class thì việc đầu tiên thường phải làm đó là có được một đối tượng kiểu Class, từ các đối tượng kiểu Class chúng ta có thể lấy được các thông tin về:

  • Class Name
  • Class Modifies (public, private, synchronized etc.)
  • Package Info
  • Superclass
  • Implemented Interfaces
  • Constructors
  • Methods
  • Fields
  • Annotations

Tạo đối tượng Class<>

Đối tượng kiểu Class được tạo ra bằng cách sử dụng phương thức static Class.forName(). Cách này thường được sử dụng khi chỉ biên được tên lớp lúc thực thi (runtime):


try {
 
    Class c =  Class.forName("com.gpcoder.Cat");
    // ...
} catch (ClassNotFoundException e) {
    System.err.println(e);
}

Trong trường hợp không tìm thấy lớp tương ứng, phương thức trên sẽ ném ra ngoại lệ ClassNotFoundException. Điều này có thể bất tiện vì bạn phải sử dụng try catch hoặc ném ngoại lệ này khỏi phương thức.

Khi bạn biết chính xác tên Lớp tại thời điểm biên dịch (combine), có thể sử dụng TenLop.class để tạo đối tượng kiểu Class. Cách này đảm bảo rằng lớp được sử dụng luôn luôn tồn tại và không có ngoại lệ nào xảy ra. Đối với các kiểu dữ liệu nguyên thủy như void, int, boolean, char,… bạn có thể dùng field TYPE để lấy được đối tượng Class tương ứng.


Class c1 = Cat.class;
Class c2 = int.class;
Class c3 = Integer.class;
Class c4 = Integer.TYPE;

Nếu bạn có một đối tượng, bạng cũng có thể lấy được đối tượng Class.


Cat cat = new Cat();
Class c = cat.getClass();

Sau đây là một ví dụ đơn giản dùng reflection để in ra các thông tin của lớp:


package com.gpcoder.reflection;

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

public class ReflectClassExample {

	public static void main(String[] args) {
		try {
			getClassInfo();
		} catch (ClassNotFoundException e) {
			e.printStackTrace();
		}
	}

	public static void getClassInfo() throws ClassNotFoundException {
		Class<?> aClazz = Class.forName("com.gpcoder.reflection.Cat");
		System.out.println("Name: " + aClazz.getName());
		System.out.println("Simple Name: " + aClazz.getSimpleName());

		Package pkg = aClazz.getPackage();
		System.out.println("Package Name = " + pkg.getName());

		// Modifier
		int modifiers = aClazz.getModifiers();
		boolean isPublic = Modifier.isPublic(modifiers);
		boolean isInterface = Modifier.isInterface(modifiers);
		boolean isAbstract = Modifier.isAbstract(modifiers);
		boolean isFinal = Modifier.isFinal(modifiers);

		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); // false

		// Lấy ra đối tượng class mô tả class cha của class Cat.
		Class<?> aSuperClass = aClazz.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
		System.out.println("\nInterface:");
		Class<?>[] itfClasses = aClazz.getInterfaces();
		for (Class<?> itfClass : itfClasses) {
			System.out.println("+ " + itfClass.getSimpleName());
		}

		// Lấy ra danh sách các cấu tử của Cat.
		System.out.println("\nConstructor:");
		Constructor<?>[] constructors = aClazz.getConstructors();
		for (Constructor<?> constructor : constructors) {
			System.out.println("+ " + constructor.getName() + " has " + constructor.getParameterCount() + " param");
		}

		// 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
		System.out.println("\nDeclared Methods:");
		Method[] methods = aClazz.getDeclaredMethods();
		for (Method method : methods) {
			System.out.println("+ " + 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
		System.out.println("\nField:");
		Field[] fields = aClazz.getFields();
		for (Field field : fields) {
			System.out.println("+ " + field.getName());
		}

		// Lấy ra danh sách các Annotation của class.
		System.out.println("\nAnnotation:");
		Annotation[] annotations = aClazz.getAnnotations();
		for (Annotation ann : annotations) {
			System.out.println("+ " + ann.annotationType().getSimpleName());
		}
	}
}

Kết quả thực thi chương trình trên:


Name: com.gpcoder.reflection.Cat
Simple Name: Cat
Package Name = com.gpcoder.reflection
Is Public? true
Is Final? false
Is Interface? false
Is Abstract? false
Simple Class Name of Super class = Animal

Interface:
+ Say

Constructor:
+ com.gpcoder.reflection.Cat has 2 param
+ com.gpcoder.reflection.Cat has 1 param
+ com.gpcoder.reflection.Cat has 0 param

Declared Methods:
+ getName
+ setName
+ say
+ getNumberOfLegs
+ setAge
+ getAge

Field:
+ SAY
+ NUMBER_OF_LEGS
+ age

Annotation:
+ Excel

Cấu tử (Constructor)

Lấy tất cả Constructor của một Class

Các đối tượng lớp Contructor là những phuơng thức khởi tạo của một lớp. Reflection cho phép lấy ra những Contructor từ Class Object:


Class aClazz = Cat.class; // obtain class object
Constructor[] constructors = aClazz.getConstructors();

Lấy một Constructor cụ thể

Nếu như bạn biết chính xác các kiểu parameter của constructor mà bạn muốn access đến thì bạn có thể lấy về đối tượng Constructor mà mình mong muốn thay vì phải lấy tất cả (một mảng).


Class aClazz = Cat.class; // obtain Class object
Constructor constructor = aClazz.getConstructor(new Class[]{String.class});

Lưu ý: Khi bạn thực hiện lấy 1 đối tượng Constructor của một lớp bất kỳ, nhưng Constructor không tồn tại thì nó sẽ quăng ra NoSuchMethodException.

Lấy danh sách tham số của một Constructor

Bạn cũng có thể truy cập được đến tham số của các Contructor, các tham số này đều được đua về kiểu Class.


Constructor constructor = ...; // obtain constructor
Class[] parameterTypes = constructor.getParameterTypes();

Khởi tạo đối tượng từ đối tượng Constructor

Có hai phương thức để tạo một thể hiện của lớp:

  • Class.newInstance(): tạo một đối tượng với constructor không có tham số.
  • Constructor.newInstance(Object[] initargs): tạo đối tượng với constructor có tham số.

// Lấy đối tượng constructor của Cat class không có tham số
Class aClazz = Cat.class; // obtain Class object
Cat cat1 = (Cat) aClazz.newInstance();

// Lấy đối tượng constructor của Cat class với argument là kiểu String
Constructor constructor = Cat.class.getConstructor(String.class);
Cat cat2 = (Cat) constructor.newInstance("Tom");

Ví dụ


package com.gpcoder.reflection;

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

public class ReflectConstructorExample {
	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ử.
		System.out.println("Params:");
		Class<?>[] paramClasses = constructor.getParameterTypes();
		for (Class<?> paramClass : paramClasses) {
			System.out.println("+ " + paramClass.getSimpleName());
		}

		// Khởi tạo đối tượng Cat theo cách thông thường.
		Cat tom = new Cat("Tom", 1);
		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ả thực thi chương trình trên:

Params:
+ String
+ int
Cat 1: Tom, age =1
Cat 2: Tom, age =2

Lưu ý:

Bởi vì Class là một lớp Generic, bạn có thể dùng kí tự wildcard để xác định kiểu dữ liệu mà nó đại diện:


Class<?> c1 = int.class;
Class<? extends Number> c2 = int.class;

Trường (Field)

Lấy các đối tượng field được khai báo là public

Bạn có thể lấy được đối tượng field được khai báo là public của một Class bằng 2 cách là chỉ lấy một field duy nhất nếu bạn biết chính xác tên của 1 field, hoặc lấy nguyên 1 mảng danh sách các field của từ một đối tượng Class.


Class aClazz = Cat.class;
Field field = aClazz.getField("name"); // Tên field cần lấy

// Lấy danh sách tất cả các field được khai báo là public
Field[] fields = aClazz.getFields();

Lưu ý: Phương thức getField() sẽ ném ra NoSuchFieldException nếu như không tồn tại Field với tên bạn đưa vào.

Lấy các đối tượng field khai báo bất kỳ

Phương thức getField() và getFields() chỉ có thể lấy các field được khai báo là public. Vậy làm sao để access được những field được khai báo là private, protected,…? Khá đơn giản, trong Java bạn có thể lấy được chúng thông qua 2 methods là getDeclaredField() và getDeclaredFields() như sau:


Class aClazz = Cat.class;
Field field = aClazz.getDeclaredField("name"); // Tên field cần lấy

// Lấy danh sách tất cả các field được khai báo là public, private, ...
Field[] fields = aClazz.getDeclaredFields();

Lưu ý: Các Exception có thể được ném ra khi gọi phương thức getDeclaredField():

  • NoSuchFieldException : Nếu tên field bạn nhập vào không tìm thấy trong Class Cat.
  • NullPointerException : Nếu tham số truyền vào là null.
  • SecurityException : Nếu có Security manager được áp dụng ở lớp này.

Lấy tên field, kiểu dữ liệu kiểu field

Sau khi bạn đã có được đối tượng Field hoặc mảng Field[] bạn muốn biết tên của Field chỉ cần gọi phương thức getName() để lấy tên field, hoặc getType() để lấy kiểu dữ liệu của field.


Class<?> aClazz = Class.forName("com.gpcoder.reflection.Cat");
Field field = aClazz.getDeclaredField("name"); // Tên field cần lấy
String fieldName = field.getName(); // Lấy tên field
Class<?> type = field.getType(); // Lấy kiểu dữ liệu của field

Gán giá trị cho Field

Gọi phương thức Field.set(Object obj, Object value): gán value cho field tương ứng của đối tượng obj.

Ví dụ


package com.gpcoder.reflection;

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

public class ReflectFieldExample {

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

		// 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
		System.out.println("Field:");
		Field[] fields = aClazz.getFields();
		for (Field field : fields) {
			System.out.println("+ " + field.getName());
		}

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

		// Ghi ra kiểu của Field
		Class<?> fieldType = field.getType();
		System.out.println("Field type: " + fieldType.getSimpleName());

		// Khởi tạo đối tượng Cat
		Cat tom = new Cat("Tom", 1);

		// Lấy ra giá trị của trường "age" theo cách của Reflect.
		Field ageField = aClazz.getField("age");
		Integer age = (Integer) ageField.get(tom);
		System.out.println("Age = " + age);

		// Gán giá trị mới cho trường "age".
		ageField.set(tom, 2);
		System.out.println("New Age = " + tom.getAge());

		// Lấy ra danh sách các Annotation của field.
		System.out.println("\nAnnotation:");
		Annotation[] annotations = ageField.getAnnotations();
		for (Annotation ann : annotations) {
			System.out.println("+ " + ann.annotationType().getSimpleName());
		}
	}

}

Kết quả thực thi chương trình trên:


Field:
+ SAY
+ NUMBER_OF_LEGS
+ age
Field type: int
Age = 1
New Age = 2

Annotation:
+ ExcelColumn

Phương thức (method)

Như đã nói ở trước đó, khi bạn sử dụng java reflection bạn có thể truy cập vào các phuơng thức của một lớp và gọi những phuơng thức này.

Lấy tất cả Method của một Class

Phương thức Class.getMethods(): trả về danh sách đối tượng Method của một lớp.


Class aClazz = Cat.class; // obtain class object
Method[] methods = aClazz.getMethods();

Lấy một Method cụ thể

Phương thức Class.getMethod(String name, Class[] parameterTypes): trả về đối tượng Method đại diện cho một phương thức của lớp. Phương thức này được xác định qua tên và các kiểu tham số.


Class aClazz = Cat.class; // obtain class object
Method method = aClazz.getMethod("setName", String.class); // get method that takes a String as argument

Thực thi một Method

Phương thức Method.invoke(Object obj, Object[] args) thực thi phương thức tương ứng của đối tượng obj với các tham số args.

Ví dụ

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ố,…


package com.gpcoder.reflection;

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

public class ReflectMethodExample {

	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> aClazz = Cat.class;

		// 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
		System.out.println("Declared Methods:");
		Method[] methods = aClazz.getDeclaredMethods();
		for (Method method : methods) {
			System.out.println("+ " + method.getName());
		}

		// Lấy ra đối tượng 'Method' mô tả method getAge()
		Method getAgeMethod = aClazz.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", 1);

		// 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 = aClazz.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(2);
		setAgeMethod.invoke(tom, 2);

		System.out.println("New Age = " + tom.getAge());
	}

}

Kết quả thực thi chương trình trên:


Declared Methods:
+ getName
+ setName
+ getNumberOfLegs
+ setAge
+ getAge
+ say
Return type of getAge: int
Age = 1
New Age = 2

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.


package com.gpcoder.reflection;

import java.lang.reflect.Method;

public class ReflectMethodExample2 {

	public static void main(String[] args) {

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

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

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

	}

	// 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;
	}

}

Kết quả thực thi chương trình trên:


Method: getName
 - Is Setter? false
 - Is Getter? true
Method: getNumberOfLegs
 - Is Setter? false
 - Is Getter? true
Method: setAge
 - Is Setter? true
 - Is Getter? false
Method: say
 - Is Setter? false
 - Is Getter? false
Method: getAge
 - Is Setter? false
 - Is Getter? true
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

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ể.

Ví dụ truy cập vào một private field.


package com.gpcoder.reflection;

import java.lang.reflect.Field;

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> aClazz = 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 = aClazz.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ả thực thi chương trình trên:


Value field name = Tom
New name = Tom Cat

Ví dụ truy cập vào một private method.


package com.gpcoder.reflection;

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

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ả thực thi chương trình trên:


New name = Tom Cat

Thay đổi giá trị field có khai báo là static final


package com.gpcoder.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

public class ChangeStaticFinalFieldExample {
	public static void main(String[] args)
			throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException {
		// create Cat
		Cat cat = new Cat();
		
		// Get field instance
		Field field = cat.getClass().getDeclaredField("NUMBER_OF_LEGS");
		field.setAccessible(true); // Suppress Java language access checking

		// Remove "final" modifier
		Field modifiersField = Field.class.getDeclaredField("modifiers");
		modifiersField.setAccessible(true);
		modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

		// Get value
		Integer fieldValue = (Integer) field.get(null);
		System.out.println(cat.getNumberOfLegs()); // -> 4

		// Set value
		field.set(null, 2);
		System.out.println(cat.getNumberOfLegs()); // -> 2
	}
}

Chú thích (Annotation)

Bạn có thể sử dụng Reflection để truy cập (access) các Annotations được áp dụng trong các class tại thời điểm Runtime.

Ví dụ tạo một Annnotation như sau:


package com.gpcoder.reflection;

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 "Defaul value";
}

Một ví dụ Annotation với class


package com.gpcoder.reflection;

import java.lang.annotation.Annotation;

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

	public static void main(String[] args) {

		Class<?> aClazz = ClassAnnotationExample.class;

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

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

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

Kết quả thực thi chương trình trên:


Annotation: MyAnnotation
Name = Table
Value = Employee

Ví dụ Annotation với Field và Method


package com.gpcoder.reflection;

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 {
		// Lấy đối tượng Class
		Class<?> aClazz = FieldMethodAnnotationExample.class;

		// Lấy đối tượng Field
		System.out.println(" == FIELD == ");
		Field field = aClazz.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 = aClazz.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ả thực thi chương trình trên:


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

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


package com.gpcoder.reflection;

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 {
		// Lấy đối tượng Class
		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());
		}
	}
}

Kết quả thực thi chương trình trên:


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

Tài liệu tham khảo:

  • https://docs.oracle.com/javase/tutorial/reflect/
  • http://o7planning.org/vi/10155/huong-dan-su-dung-java-reflection
  • https://yinyangit.wordpress.com/2011/11/12/java-tim-hieu-ve-reflection-runtime-type-information/
  • http://java-performance.info/updating-final-and-static-final-fields/
4.9
14
Nếu bạn thấy hay thì hãy chia sẻ bài viết cho mọi người nhé! Và Donate tác giả

Shares

Chuyên mục: Reflection Được gắn thẻ: Annotation, Reflection

Hướng dẫn sử dụng Java Generics
Hướng dẫn sử dụng Java Annotation

Có thể bạn muốn xem:

  • Làm thế nào tạo instance của một class mà không gọi từ khóa new? (25/04/2019)
  • Kết hợp Java Reflection và Java Annotations (05/12/2017)
  • Marker Interface trong Java (30/03/2020)

Bình luận

bình luận

Tìm kiếm

Bài viết mới

  • Clean code 13/01/2024
  • Giới thiệu CloudAMQP – Một RabbitMQ server trên Cloud 02/10/2020
  • Kết nối RabbitMQ sử dụng Web STOMP Plugin 19/06/2020
  • Sử dụng publisher confirm trong RabbitMQ 16/06/2020
  • Sử dụng Dead Letter Exchange trong RabbitMQ 13/06/2020

Xem nhiều

  • Hướng dẫn Java Design Pattern – Factory Method (97657 lượt xem)
  • Hướng dẫn Java Design Pattern – Singleton (97342 lượt xem)
  • Giới thiệu Design Patterns (87178 lượt xem)
  • Lập trình đa luồng trong Java (Java Multi-threading) (85895 lượt xem)
  • Giới thiệu về Stream API trong Java 8 (83401 lượt xem)

Nội dung bài viết

  • 1 Java Reflection là gì?
  • 2 Một số class được sử dụng trong bài viết này
  • 3 Kiến trúc của Java Reflection API

Lưu trữ

Thẻ đánh dấu

Annotation Authentication Basic Java Behavior Pattern Collection Creational Design Pattern Cấu trúc điều khiển Database Dependency Injection Design pattern Eclipse Exception Executor Service Google Guice Gson Hibernate How to Interceptor IO Jackson Java 8 Java Core JDBC JDK Jersey JMS JPA json JUnit JWT Message Queue Mockito Multithreading OOP PowerMockito RabbitMQ Reflection Report REST SOAP Structuaral Pattern Swagger Thread Pool Unit Test Webservice

Liên kết

  • Clean Code
  • JavaTpoint
  • Refactoring Guru
  • Source Making
  • TutorialsPoint
  • W3Schools Online Web Tutorials

Giới thiệu

GP Coder là trang web cá nhân, được thành lập với mục đích lưu trữ, chia sẽ kiến thức đã học và làm việc của tôi. Các bài viết trên trang này chủ yếu về ngôn ngữ Java và các công nghệ có liên quan đến Java như: Spring, JSF, Web Services, Unit Test, Hibernate, SQL, ...
Hi vọng góp được chút ít công sức cho sự phát triển cộng đồng Coder Việt.

Donate tác giả

Tìm kiếm các bài viết của GP Coder với Google Search

Liên hệ

Các bạn có thể liên hệ với tôi thông qua:
  • Trang liên hệ
  • Linkedin: gpcoder
  • Email: contact@gpcoder.com
  • Skype: ptgiang56it

Follow me

Copyright 2025 © GP Coder · All Rights Reserved · Giới thiệu · Chính sách · Điều khoản · Liên hệ ·

Share

Blogger
Delicious
Digg
Email
Facebook
Facebook messenger
Flipboard
Google
Hacker News
Line
LinkedIn
Mastodon
Mix
Odnoklassniki
PDF
Pinterest
Pocket
Print
Reddit
Renren
Short link
SMS
Skype
Telegram
Tumblr
Twitter
VKontakte
wechat
Weibo
WhatsApp
X
Xing
Yahoo! Mail

Copy short link

Copy link