Java 反射机制详解(四)

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

猜你喜欢

转载自blog.csdn.net/nioqnw/article/details/84628848