怎样用反射对Constructor对象、Field对象、Method对象进行操作

1、概念和使用场景

1.1 反射概念

​ 反射是Java中的一种机制,我的编写好的Java文件是不能直接运行,需要编译成class文件,jvm将Class文件加载进内存,并读取Class文件中的内容(该内容就是我们类中写的东西)封装成一个Class对象,并且类的各个组成部分也都被封装成一个个对象。成员变量会被封装成Field对象,构造方法会被封装成Constructor对象,成员方法会被封装成Method对象,这些对象都统一保存在Class对象身上。Java中的反射机制就是要求我们通过Class对象操作Field、Constructor、Method对象完成数据的封装。

1.2 使用场景

反射是框架设计的核心部分。

2、获取Class对象的三种方法及其作用

2.1 三种方式

1 通过类名获取Class对象
  Class clazz=类名.class;
2 通过对象获取Class对象
  Class clazz=对象.getClass();
3 通过Class类型的forName()静态方法获取
  Class clazz=Class.forName("全类名");  //报名.类名

2.2 代码演示

public class ReflectClass {
  public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
    //1 通过类名获取Class对象
    Class<User> userClass = User.class;
    System.out.println(userClass);

    //2 通过对象获取Class对象
    User user=new User();
    Class<? extends User> userClass2 = user.getClass();
    System.out.println(userClass2);

    //3 通过Class类型的forName()静态方法获取
    Class<?> userClass3 = Class.forName("com.domain.User");
    System.out.println(userClass3);

    //userClass、userClass2、userClass3是否是同一个对象? 是的
    System.out.println(userClass==userClass2);
    System.out.println(userClass==userClass3);

    //Class对象的作用?
    //1 可以获取成员变量对象(Field)、获取成员方法对象(Method)、获取构造方法对象(Constructor)
    //2 可以实例化一个User对象,默认执行的是空参构造
    User u = userClass.newInstance();
    System.out.println("u = " + u);
    //3 获取类上的注解参数值
    Resource resource = userClass.getAnnotation(Resource.class);
    String name = resource.name();
    System.out.println("name = " + name);
  }
}

3、获取Constructor对象及其作用

3.1 API

1.获取构造方法对象
	Constructor<?>[] getConstructors() 获取所有public修饰的构造方法
	Constructor<T> getConstructor(Class<?>... parameterTypes) 获取指定参数类型的public修饰的构造方法
	Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型的任意修饰符类型的构造方法
	Constructor<?>[] getDeclaredConstructors() 获取任意修饰符类型所有的构造方法

方法规律:
	1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
	2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
  
2.实例化对象
  Object obj=constructor.newInstance(Object...param);创建对象,并且传递构造需要的参数

3.2 代码演示

package com.itheima_1;

import com.domain.User;

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

/*
    1.获取构造方法对象
	Constructor<?>[] getConstructors() 获取所有public修饰的构造方法
	Constructor<T> getConstructor(Class<?>... parameterTypes) 获取指定参数类型的public修饰的构造方法
	Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型的任意修饰符类型的构造方法
	Constructor<?>[] getDeclaredConstructors() 获取任意修饰符类型所有的构造方法

	方法规律:
	    1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
	    2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
 */
public class ReflectConstructor {
  public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
    //1 获取Class对象
    Class<User> userClass = User.class;

    //2 获取Constructor对象
    //Constructor<?>[] getConstructors() 获取所有public修饰的构造方法
    //        Constructor<?>[] constructors = userClass.getConstructors();

    //Constructor<?>[] getDeclaredConstructors() 获取任意修饰符类型所有的构造方法
    /*Constructor<?>[] constructors = userClass.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            System.out.println(constructor);
        }
*/
    //Constructor<T> getConstructor(Class<?>... parameterTypes) 获取指定参数类型的public修饰的构造方法
    //        Constructor<User> constructor = userClass.getConstructor();

    //Constructor<T> getDeclaredConstructor(Class<?>... parameterTypes) 获取指定参数类型的任意修饰符类型的构造方法
    Constructor<User> constructor = userClass.getDeclaredConstructor();

    System.out.println(constructor);

    //3 Constructor的相关操作
    //主要就是实例化对象
    //        User user = constructor.newInstance();

    //取消访问权限,又叫暴力访问
    constructor.setAccessible(true);
    User user = constructor.newInstance("java89期 杨焕"); //User user=new User("java89期 杨焕");
    System.out.println(user);

  }
}

注意:如果构造是非public修饰的,那么在实例化对象之前调用setAccessible(true);取消访问权限(暴力访问)。

4、获取Field对象及其作用

4.1 API

1.获取成员变量对象
  Field[] getFields() :获取所有public修饰的成员变量
  Field getField(String name) 获取一个指定名称的public修饰的成员变量
  Field[] getDeclaredFields() 获取所有的任意修饰符类型成员变量
  Field getDeclaredField(String name) 获取任意修饰符类型指定名称的成员变量
  
方法规律:
	1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
	2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
  
2.赋值和取值
	field.get(Object obj);获取哪个对象的field成员变量值;
	field.set(Object obj, Object value);设置obj对象的field成员变量值为value

4.2 代码演示

public class ReflectField {
  public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, InstantiationException {
    //1 获取Class对象
    Class<User> userClass = User.class;

    //2 获取Field成员变量对象
    //Field[] getFields() :获取所有public修饰的成员变量
    //Field[] fields = userClass.getFields();

    //Field[] getDeclaredFields() 获取所有的任意修饰符类型成员变量
    /*Field[] fields = userClass.getDeclaredFields();
        for (Field field : fields) {
            System.out.println(field);
        }*/

    //Field getField(String name) 获取一个指定名称的public修饰的成员变量
    //        Field field = userClass.getField("name");

    //Field getDeclaredField(String name) 获取任意修饰符类型指定名称的成员变量
    Field field = userClass.getDeclaredField("age");
    System.out.println(field);

    //3 操作Field对象
    //取消访问权限
    field.setAccessible(true);
    //赋值,field.set(Object obj, Object value);设置obj对象的field成员变量值为value
    User user = userClass.newInstance();
    field.set(user,20);
    System.out.println(user);

    //取值,field.get(Object obj);获取哪个对象的field成员变量值;
    Object age = field.get(user);
    System.out.println("age = " + age);

    //其他操作
    //获取变量名称
    System.out.println(field.getName());
    //获取变量类型
    System.out.println(field.getGenericType().getTypeName());
    //获取修饰符类型
    int modifier = field.getModifiers();
    System.out.println(Modifier.toString(modifier));
    //System.out.println(Modifier.isPrivate(modifier));
  }
}

注意:如果构造是非public修饰的,那么在调用set()/get()方法之前调用setAccessible(true)取消访问权限(暴力访问)。

5、获取Method对象及其作用

5.1 API

1.获取成员方法对象
	Method[] getMethods() 获取所有public修饰的方法(可以获取父类的public修饰的方法)
	Method getMethod(String name, Class<?>... parameterTypes) 获取一个指定名称指定参数类型的public修饰成员方法
	Method[] getDeclaredMethods() 获取任意修饰符类型所有的成员方法
	Method getDeclaredMethod(String Class,<?>... parameterTypes) 获取一个指定名称指定参数类型的任意修饰符类型成员方法

方法规律:
	1 方法带Declared表示获取任意修饰符修饰的对象,否则只能获取public修饰的对象
	2 方法带s表示获取多个对象,不带s表示获取指定名称的对象
  
2.执行方法
  method.invoke(Object obj, Object... args);执行obj对象身上的method方法并给方法传递的参数值为args。

5.2 代码演示

public class ReflectMethod {
  public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
    //1 获取Class对象
    Class<User> userClass = User.class;

    //2 获取Method对象
    //Method[] getMethods() 获取所有public修饰的方法(可以获取父类的public修饰的方法)
    //Method[] methods = userClass.getMethods();

    //Method[] getDeclaredMethods() 获取任意修饰符类型所有的成员方法
    /*Method[] methods = userClass.getDeclaredMethods();
        for (Method method : methods) {
            System.out.println(method);
        }*/

    //Method getMethod(String name, Class<?>... parameterTypes) 获取一个指定名称指定参数类型的public修饰成员方法
    //Method method = userClass.getMethod("setName", String.class);

    //Method getDeclaredMethod(String Class, 类<?>... parameterTypes) 获取一个指定名称指定参数类型的任意修饰符类型成员方法
    //Method method = userClass.getDeclaredMethod("show1");
    Method method = userClass.getDeclaredMethod("show1", String.class);
    System.out.println(method);

    //3 操作Method对象
    //主要是执行方法
    //method.invoke(Object obj, Object... args);执行obj对象身上的method方法并给方法传递的参数值为args。
    //暴力访问
    method.setAccessible(true);
    User user = userClass.newInstance();
    Object value = method.invoke(user, "吴文波");
    System.out.println("value = " + value);

    //其他使用
    //获取方法名
    System.out.println(method.getName());
    //获取返回值类型
    System.out.println(method.getReturnType().getSimpleName());
    //返回修饰符类型
    System.out.println(Modifier.toString(method.getModifiers()));
    System.out.println(Modifier.isStatic(method.getModifiers()));
    //获取参数类型
    Class<?>[] parameterTypes = method.getParameterTypes();
    for (Class<?> parameterType : parameterTypes) {
      System.out.println(parameterType.getSimpleName());
    }
    //获取方法上的注解
    Resource resource = method.getAnnotation(Resource.class);
    System.out.println(resource.name());
  }

注意:如果构造是非public修饰的,那么在调用invoke()方法之前调用setAccessible(true)取消访问权限(暴力访问)。

6、反射总结

核心:掌握反射操作的基本思路

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RUJ4iWNd-1587303757539)(img/反射知识点结构图.png)]

7、反射案例

7.1 需求

​ 设计一个BeanUtils工具类,该工具类的作用是将Map<String,Object>集合中的数据封装到对应的JavaBean中。

7.2 代码实现

public class BeanUtils {
    /**
     * 将Map<String,Object>集合中的数据封装到对应的bean对象中。
     * @param bean 要封装数据的bean对象
     * @param map 存储数据的map集合
     * 方式1:通过反射Field对象的方式封装
     */
    /*public static void populate(Object bean, Map<String,Object> map) throws IllegalAccessException {
        //1 获取Class对象
        Class<?> aClass = bean.getClass();

        //2 获取所有field对象
        Field[] fields = aClass.getDeclaredFields();

        //3 遍历所有的Field对象
        for (Field field : fields) {
            //4 遍历map集合,获取所有的key和value
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                String key = entry.getKey();
                Object value = entry.getValue();
                //5 判断key是否和field名称一致,如果一致就封装数据
                if(key.equals(field.getName())){
                    //取消访问权限
                    field.setAccessible(true);
                    field.set(bean,value);
                }
            }
        }
    }*/

    /**
     * 将Map<String,Object>集合中的数据封装到对应的bean对象中。
     * @param bean 要封装数据的bean对象
     * @param map 存储数据的map集合
     * 方式2:通过反射setXxx方法的方式封装
     */
    /*public static void populate(Object bean, Map<String,Object> map) throws IllegalAccessException, InvocationTargetException, NoSuchMethodException {
        //1 获取Class对象
        Class<?> aClass = bean.getClass();

        //2 获取所有Method对象
        Method[] methods = aClass.getDeclaredMethods();

        //3 遍历所有的Method对象
        for (Method method : methods) {
            //4 遍历map集合,获取所有的key和value
            Set<Map.Entry<String, Object>> entries = map.entrySet();
            for (Map.Entry<String, Object> entry : entries) {
                String key = entry.getKey();//name,age,man,birthday
                Object value = entry.getValue();
                //5 判断"set"+key是否和Method名称一致,如果一致就封装数据
                if(method.getName().equalsIgnoreCase("set"+key)){
                    //执行方法
                    method.invoke(bean,value);
                }
            }
        }
    }*/

    /**
     * 将Map<String,Object>集合中的数据封装到对应的bean对象中。
     * @param bean 要封装数据的bean对象
     * @param map 存储数据的map集合
     * 方式3:通过java内省机制的方式封装
     */
    public static void populate(Object bean, Map<String,Object> map) throws IllegalAccessException, InvocationTargetException, IntrospectionException {
        //1 获取Class对象
        Class<?> aClass = bean.getClass();
        //2 遍历map集合,获取所有的key和value
        Set<Map.Entry<String, Object>> entries = map.entrySet();
        for (Map.Entry<String, Object> entry : entries) {
            String key = entry.getKey(); //name,age,man,birthday
            Object value = entry.getValue();
            //3 根据key创建属性描述器对象,获取setXxx属性方法
            PropertyDescriptor pd=new PropertyDescriptor(key,aClass);
            //获取setXxx属性方法
            Method method = pd.getWriteMethod();
            //4 执行该方法
            method.invoke(bean,value);
        }
    }
}

8、Java的内省机制

Java的内省机制:Java中提供了一种机制,专门用来获取javabean的属性信息。由三类类操作javabean的属性。

public class IntrospectDemo {
  public static void main(String[] args) throws IntrospectionException {
    //获取javabean信息
    BeanInfo beanInfo = Introspector.getBeanInfo(User.class);
    //获取所有的属性方法:setXxx()或者getXxx()
    PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
    for (PropertyDescriptor propertyDescriptor : propertyDescriptors) {
      //获取setXxx()
      System.out.println(propertyDescriptor.getWriteMethod());
      //获取getXxx()
      System.out.println(propertyDescriptor.getReadMethod());
    }
    //获取指定名称的setXxx()和getXxx()方法
    PropertyDescriptor propertyDescriptor=new PropertyDescriptor("name",User.class);
    System.out.println(propertyDescriptor.getWriteMethod());
    System.out.println(propertyDescriptor.getReadMethod());
  }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值