Java 反射机制详解(四)
4. 反射与泛型
定义一个泛型类:
public class DAO<T> {
//根据id获取一个对象
T get(Integer id){
return null;
}
//保存一个对象
void save(T entity){
}
}
再定义一个子类,继承这个泛型类:
public class PersonDAO extends DAO<Person> {
}
父类中的泛型T,就相当于一个参数,当子类继承这个类时,就要给这个参数赋值,这里是把Person类型传给了父类,还有一种做法 :
public class PersonDAO<T> extends DAO<T> {
}
进行测试:
@Test
public void testAnnotation() throws Exception{
PersonDAO personDAO = new PersonDAO();
Person entity = new Person();
//调用父类的save方法,同时也把Person这个“实参”传给了父类的T
personDAO.save(entity);
//这句的本意是要返回一个Person类型的对象
Person result = personDAO.get(1);
System.out.print(result);
}
问题出来了。这里的get方法是父类的get方法,对于父类而言,方法返回值是一个T类型,当T的值为Person时,本该返回一个Person类型,但是必须用反射来创建这个对象(泛型方法返回一个对象),方法无非就是clazz.newInstance(),所以关键点就是根据T得到其对于的Class对象。那么首先,在父类中定义一个字段,表示T所对应的Class,然后想办法得到这个clazz的值
public class DAO<T> {
private Class<T> clazz;
T get(Integer id){
return null;
}
}
如何获得这个clazz呢?
@Test
public void test() throws Exception{
PersonDAO personDAO = new PersonDAO();
Person result = personDAO.get(1);
System.out.print(result);
}
public DAO(){
//1.
System.out.println("DAO's Constrctor...");
System.out.println(this); //结果是:com.atguigu.java.fanshe.PersonDAO@66588ec0
//this:父类构造方法中的this指的是子类对象,因为此时是PersonDAO对象在调用
System.out.println(this.getClass()); //结果是:class com.atguigu.java.fanshe.PersonDAO
//2.
//获取DAO子类的父类
Class class1 = this.getClass().getSuperclass();
System.out.println(class1); //结果是:class com.atguigu.java.fanshe.DAO
//此时只能获的父类的类型名称,却不可以获得父类的泛型参数
//3.
//获取DAO子类带泛型参数的子类
Type type=this.getClass().getGenericSuperclass();
System.out.println(type); //结果是:com.atguigu.java.fanshe.DAO<com.atguigu.java.fanshe.Person>
//此时获得了泛型参数,然后就是把它提取出来
//4.
//获取具体的泛型参数 DAO<T>
//注意Type是一个空的接口,这里使用它的子类ParameterizedType,表示带参数的类类型(即泛型)
if(type instanceof ParameterizedType){
ParameterizedType parameterizedType = (ParameterizedType) type;
Type [] arges = parameterizedType.getActualTypeArguments();
System.out.println(Arrays.asList(arges)); //结果是:[class com.atguigu.java.fanshe.Person]
//得到的是一个数组,因为可能父类是多个泛型参数public class DAO<T,PK>{}
if(arges != null && arges.length >0){
Type arg = arges[0];
System.out.println(arg); //结果是:class com.atguigu.java.fanshe.Person
//获得第一个参数
if(arg instanceof Class){
clazz = (Class<T>) arg;
//把值赋给clazz字段
}
}
}
}
所以就定义一个方法,获得 Class 定义中声明的父类的泛型参数类型
public class ReflectionTest {
/**
* 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型
* 如: public EmployeeDao extends BaseDao<Employee, String>
* @param clazz: 子类对应的 Class 对象
* @param index: 子类继承父类时传入的泛型的索引. 从 0 开始
* @return
*/
@SuppressWarnings("unchecked")
public Class getSuperClassGenricType(Class clazz, int index){
Type type = clazz.getGenericSuperclass();
if(!(type instanceof ParameterizedType)){
return null;
}
ParameterizedType parameterizedType =
(ParameterizedType) type;
Type [] args = parameterizedType.getActualTypeArguments();
if(args == null){
return null;
}
if(index < 0 || index > args.length - 1){
return null;
}
Type arg = args[index];
if(arg instanceof Class){
return (Class) arg;
}
return null;
}
@SuppressWarnings("unchecked")
public Class getSuperGenericType(Class clazz){
return getSuperClassGenricType(clazz, 0);
}
@Test
public void testGetSuperClassGenricType(){
Class clazz = PersonDAO.class;
//PersonDAO.class
Class argClazz = getSuperClassGenricType(clazz, 0);
System.out.println(argClazz);
//结果是class com.atguigu.java.fanshe.Person
}
}
反射小结
1. Class: 是一个类; 一个描述类的类.
封装了描述方法的 Method,描述字段的 Filed,描述构造器的 Constructor 等属性.
2. 如何得到 Class 对象:
2.1 Person.class
2.2 person.getClass()
2.3 Class.forName("com.atguigu.javase.Person")
3. 关于 Method:
3.1 如何获取 Method:
a. getDeclaredMethods: 得到 Method 的数组.
b. getDeclaredMethod(String methondName, Class ... parameterTypes)
3.2 如何调用 Method
a. 如果方法时 private 修饰的, 需要先调用 Method 的 setAccessible(true), 使其变为可访问
b. method.invoke(obj, Object ... args);
4. 关于 Field:
4.1 如何获取 Field: getField(String fieldName)
4.2 如何获取 Field 的值:
a. setAccessible(true)
b. field.get(Object obj)
4.3 如何设置 Field 的值:
field.set(Obejct obj, Object val)
5. 了解 Constructor 和 Annotation
6. 反射和泛型.
6.1 getGenericSuperClass: 获取带泛型参数的父类, 返回值为: BaseDao<Employee, String>
6.2 Type 的子接口: ParameterizedType
6.3 可以调用 ParameterizedType 的 Type[] getActualTypeArguments() 获取泛型参数的数组.
附:反射的 Utils 函数集合
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
/**
* 反射的 Utils 函数集合
* 提供访问私有变量, 获取泛型类型 Class, 提取集合中元素属性等 Utils 函数
* @author Administrator
*
*/
public class ReflectionUtils {
/**
* 通过反射, 获得定义 Class 时声明的父类的泛型参数的类型
* 如: public EmployeeDao extends BaseDao<Employee, String>
* @param clazz
* @param index
* @return
*/
@SuppressWarnings("unchecked")
public static Class getSuperClassGenricType(Class clazz, int index){
Type genType = clazz.getGenericSuperclass();
if(!(genType instanceof ParameterizedType)){
return Object.class;
}
Type [] params = ((ParameterizedType)genType).getActualTypeArguments();
if(index >= params.length || index < 0){
return Object.class;
}
if(!(params[index] instanceof Class)){
return Object.class;
}
return (Class) params[index];
}
/**
* 通过反射, 获得 Class 定义中声明的父类的泛型参数类型
* 如: public EmployeeDao extends BaseDao<Employee, String>
* @param <T>
* @param clazz
* @return
*/
@SuppressWarnings("unchecked")
public static<T> Class<T> getSuperGenericType(Class clazz){
return getSuperClassGenricType(clazz, 0);
}
/**
* 循环向上转型, 获取对象的 DeclaredMethod
* @param object
* @param methodName
* @param parameterTypes
* @return
*/
public static Method getDeclaredMethod(Object object, String methodName, Class<?>[] parameterTypes){
for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
try {
//superClass.getMethod(methodName, parameterTypes);
return superClass.getDeclaredMethod(methodName, parameterTypes);
} catch (NoSuchMethodException e) {
//Method 不在当前类定义, 继续向上转型
}
//..
}
return null;
}
/**
* 使 filed 变为可访问
* @param field
*/
public static void makeAccessible(Field field){
if(!Modifier.isPublic(field.getModifiers())){
field.setAccessible(true);
}
}
/**
* 循环向上转型, 获取对象的 DeclaredField
* @param object
* @param filedName
* @return
*/
public static Field getDeclaredField(Object object, String filedName){
for(Class<?> superClass = object.getClass(); superClass != Object.class; superClass = superClass.getSuperclass()){
try {
return superClass.getDeclaredField(filedName);
} catch (NoSuchFieldException e) {
//Field 不在当前类定义, 继续向上转型
}
}
return null;
}
/**
* 直接调用对象方法, 而忽略修饰符(private, protected)
* @param object
* @param methodName
* @param parameterTypes
* @param parameters
* @return
* @throws InvocationTargetException
* @throws IllegalArgumentException
*/
public static Object invokeMethod(Object object, String methodName, Class<?> [] parameterTypes,
Object [] parameters) throws InvocationTargetException{
Method method = getDeclaredMethod(object, methodName, parameterTypes);
if(method == null){
throw new IllegalArgumentException("Could not find method [" + methodName + "] on target [" + object + "]");
}
method.setAccessible(true);
try {
return method.invoke(object, parameters);
} catch(IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return null;
}
/**
* 直接设置对象属性值, 忽略 private/protected 修饰符, 也不经过 setter
* @param object
* @param fieldName
* @param value
*/
public static void setFieldValue(Object object, String fieldName, Object value){
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
try {
field.set(object, value);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
}
/**
* 直接读取对象的属性值, 忽略 private/protected 修饰符, 也不经过 getter
* @param object
* @param fieldName
* @return
*/
public static Object getFieldValue(Object object, String fieldName){
Field field = getDeclaredField(object, fieldName);
if (field == null)
throw new IllegalArgumentException("Could not find field [" + fieldName + "] on target [" + object + "]");
makeAccessible(field);
Object result = null;
try {
result = field.get(object);
} catch (IllegalAccessException e) {
System.out.println("不可能抛出的异常");
}
return result;
}
}
原文链接:https://www.cnblogs.com/tech-bird/p/3525336.html