java 反射 的详细总结

1.前言

  什么是反射?

引用教科书的解释:

在运行状态中,对于任意一个实体类,都能够知道这个类的所有属性和方法;
对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为java语言的反射机制。

  如何通俗理解?

其实说白了,就是将任意一个类对象【原对象】注入一个反射类里,可以对原对象解析,
获取里面的所有属性和方法信息,并可以调用;使用原对象获取对象类型后获取无参构造函数再实例一个无参对象,
那么这个对象就是该原对象的反射对象,反射对象有着与原对象一样的属性和方法,可以动态获取任意对象信息和动态的调用任意对象方法,
如果不做其他增强操作,就相当于反射对象复制了原对象。
由此可见,可以调用原方法的同时做一些其他操作,也就是增强操作,这也就是动态代理的底层原理。

2.操作

使用代码理解【里面有很多注释,足够理解了啊】

(1)文件目录结构

 (2)建一个实体类

package com.example.javabaisc.reflect.deme;

import java.util.HashMap;
import java.util.UUID;

/**
 * 实体类
 */
public class Info {
    //被保护的属性
    private int id;
    private String name;
    //无参构造函数
    public Info(){};
    //有参构造函数
    public Info(int id ,String name){
        this.id = id ;
        this.name = name;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //共有自定义方法
    public String dosomething(String str){
        System.out.println("我是自定义方法,输入参数是="+str);
        return str+"==="+ UUID.randomUUID().toString();
    }

    //私有被保护的自定义方法
    private String love(int num){
        System.out.println("我是自定义方法,输入参数是="+num);
        return num+"==="+ UUID.randomUUID().toString();
    }
    //公共使用属性
    public String publicParam;


}
View Code

有各种属性和方法

(3)反射类

package com.example.javabaisc.reflect.deme;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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

/**
 * 反射类
 */
public class DoReflect {

    Logger logger = LoggerFactory.getLogger(getClass());

    /*
    反射方法【类似于复制操作】
     */
    public Object copy(Object object) throws Exception {
        /**
         * 获取传入原对象的类型
         */
        // 写法1:【泛型可写可不写】
        Class<?> classType = object.getClass();
        logger.warn("获取传入原对象的类型:" + classType.getName());
        //写法2:
        //原对象的文件路径【注意,没有文件java后缀,不建议这样使用,否则需要传入路对象文件路径】
//        String infoURL = "com.example.javabaisc.reflect.deme.Info";
//        Class<? > classType = Class.forName(infoURL);
        //
        //写法3:
        //原对象的文件路径【不建议这样使用,否则需要传入路对象文件路径】
//        String infoURL =  "com.example.javabaisc.reflect.deme.Info";
//        Class<?> classType = DoReflect.class.getClassLoader().loadClass(infoURL);
        //
        //看看,方法2和3 是不是很眼熟,就是以前使用原生的jdbc连接数据库放入操作啊,原来jdbc底层是使用了映射。。。
        //但是还是方法1简单,而且容易理解
        //
        //
        /**
         *  根据原对象类型,获取无参构造函数后实例一个新的对象,这个就是映射对象
         */
        //如果newInstance没有参数,则可以不写空的超类数组
        Object objectCopy = classType.getConstructor(new Class[]{}).newInstance(new Object[]{});
//        //上面一句话可以分步写:
//        //步骤1:获取无参构造函数对象
//        Constructor<?> constructor = classType.getConstructor(new Class[]{});
//        logger.warn("无参构造函数对象名字:" + constructor.getName());
//        //步骤2:获反射对象
//        Object objectCopy = constructor.newInstance(new Object[]{});
        logger.warn("反射对象名字:" + objectCopy.toString());
        //
        /**
         * 获取所有方法
         */
        Method[] methods = classType.getDeclaredMethods();
        logger.warn("===================================================================");
        for (Method method : methods) {
            /*
            获取方法修饰符
             */
            String modifier = Modifier.toString(method.getModifiers());
            logger.warn("获取方法修饰符:" + modifier);
            /*
            获取返回参数类型
             */
//            [会获取完整的类型路径名,如 java.lang.String]
            String returnType = method.getReturnType().getName();
            logger.warn("获取返回参数类型,写法1:" + returnType);
//            [仅会获取名字,如String]
            String returnType2 = method.getReturnType().getSimpleName();
            logger.warn("获取返回参数类型,写法2:" + returnType2);
            /*
            获取方法名字
             */
            String methodName = method.getName();
            logger.warn("获取方法名字:" + methodName);
            //获取所有传入参数类型
            Class<?>[] params = method.getParameterTypes();
            logger.warn("------------------------------------------------------------");
            for (Class<?> param : params) {
                /*
                获取参数类型名字
                 */
                //写法1和2都是获取完整的类型路径名,如 java.lang.String
                String paramTypeName = param.getName();
                String paramTypeName2 = param.getTypeName();
                //该写法3仅会获取类型名字,如String
                String paramTypeName3 = param.getSimpleName();
                logger.warn("获取参数类型名字,写法1:" + paramTypeName);
                logger.warn("获取参数类型名字,写法2:" + paramTypeName2);
                logger.warn("获取参数类型名字,写法3:" + paramTypeName3);
            }
            logger.warn("------------------------------------------------------------");
        }
        logger.warn("===================================================================");

        /**
         * 获取指定的方法
         */
        logger.warn("使用getMethod获取指定的方法,但是仅能获取public修饰的方法");
        //参数分别是 方法名字 、参数类型
        Method method = classType.getMethod("dosomething", new Class[]{String.class});
        // 指定方法的修饰符
        String modifier = Modifier.toString(method.getModifiers());
        logger.warn("指定方法的修饰符:" + modifier);
        String returnTypeName = method.getReturnType().getSimpleName();
        logger.warn("指定方法的返回类型:" + returnTypeName);
        //指定方法的名子
        String methodName = method.getName();
        logger.warn("指定方法的名子:" + methodName);
        Class<?>[] params = method.getParameterTypes();
        for (Class<?> param : params) {
            logger.warn("指定方法的参数类型:" + param.getSimpleName());
        }
        logger.warn("===================================================================");
        logger.warn("使用privateMethod获取指定的方法,可以获取被保护的方法");
        //参数分别是 方法名字 、参数类型
        Method privateMethod = classType.getDeclaredMethod("love", new Class[]{int.class});
        // 指定方法的修饰符
        String modifier2 = Modifier.toString(privateMethod.getModifiers());
        logger.warn("指定方法的修饰符:" + modifier2);
        String returnTypeName2 = privateMethod.getReturnType().getSimpleName();
        logger.warn("指定方法的返回类型:" + returnTypeName2);
        //指定方法的名子
        String methodName2 = privateMethod.getName();
        logger.warn("指定方法的名子:" + methodName2);
        Class<?>[] params2 = privateMethod.getParameterTypes();
        for (Class<?> param : params2) {
            logger.warn("指定方法的参数类型:" + param.getSimpleName());
        }

        logger.warn("===================================================================");
        /**
         * 获取所有属性
         */
        logger.warn("获取所有属性");
        Field[] fields = classType.getDeclaredFields();
        logger.warn("------------------------------------------------------------");
        for (Field field : fields) {
            //属性修饰符
            String modifer = Modifier.toString(field.getModifiers());
            logger.warn("属性修饰符:" + modifer);
            //属性类型
            String fieldType = field.getType().getSimpleName();
            logger.warn("属性类型:" + fieldType);
            //属性名字
            String fieldName = field.getName();
            logger.warn("字段名字:" + fieldName);
        }
        logger.warn("------------------------------------------------------------");
        logger.warn("===================================================================");
        /**
         * 获取指定属性
         */
        logger.warn("使用getField获取指定属性,但是仅能获取public修饰的属性");
        Field field = classType.getField("publicParam");
        //属性修饰符
        String modifer = Modifier.toString(field.getModifiers());
        logger.warn("属性修饰符:" + modifer);
        //属性类型
        String fieldType = field.getType().getSimpleName();
        logger.warn("属性类型:" + fieldType);
        //属性名字
        String fieldName = field.getName();
        logger.warn("字段名字:" + fieldName);
        logger.warn("------------------------------------------------------------");
        logger.warn("使用getDeclaredField获取指定属性,可以获取被保护的属性");
        Field field2 = classType.getDeclaredField("id");
        //属性修饰符
        String modifer2 = Modifier.toString(field2.getModifiers());
        logger.warn("属性修饰符:" + modifer2);
        //属性类型
        String fieldType2 = field2.getType().getSimpleName();
        logger.warn("属性类型:" + fieldType2);
        //属性名字
        String fieldName2 = field2.getName();
        logger.warn("字段名字:" + fieldName2);
        logger.warn("===================================================================");
        /**
         * 调用对象的方法,
         * 首先需要获取方法对象,然后通过参数来选择是调用原对象的方法还是反射对象的方法
         */
        logger.warn("调用对象的方法");
        /*
        向原对象 setname 传入name值,然后 getname 获取原对象name值,然后将获取的值使用反射对象的 setname 方传入后,使用反射对象的 getname 获取
         */
        //拼接 setname 方法名字
        String setMethodName = "set" + ("name".substring(0, 1).toUpperCase()) + ("name".substring(1));
        //拼接 getname 方法名字
        String getMethodName = "get" + ("name".substring(0, 1).toUpperCase()) + ("name".substring(1));
        //获取 setname 方法对象
        Method setMethod = classType.getDeclaredMethod(setMethodName, new Class[]{String.class});
        //获取 getname 方法对象
        Method getMethod = classType.getDeclaredMethod(getMethodName, new Class[]{});
        //调用原对象的 setname方法,并赋值
        String mname = "你大爷啊啊啊";
        setMethod.invoke(object, new Object[]{mname});
        //调用原对象的 getname方法 获取name值
        Object value = getMethod.invoke(object, new Object[]{});
        logger.warn("调用 原对象 的 getname方法 获取name值为:" + value);
        //调用反射对象的 setname方法,并赋值
        setMethod.invoke(objectCopy, new Object[]{value});
        //调用反射对象的 getname方法 获取name值
        Object reflectValue = getMethod.invoke(objectCopy, new Object[]{});
        logger.warn("调用 反射对象 的 getname方法 获取name值为:" + reflectValue);
        logger.warn("===================================================================");


        //返回反射对象
        return objectCopy;

    }


}
View Code

(4)测试类

package com.example.javabaisc.reflect.deme;

import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 测试类
 */
public class RETest {
    Logger log = LoggerFactory.getLogger(getClass());

    @Test
    public void t() throws Exception {

        //实例实体类
        Info info = new Info();
        //实例反射类
        DoReflect doReflect = new DoReflect();
        //调用反射类的反射方法,将实体类对象注入进去 ,返回这个实体类的反射对象
        Info infoReflect = (Info) doReflect.copy(info);
        //调用反射对象的方法
        String res = infoReflect.dosomething("扫地啦");
        log.warn("调用反射对象的方法的结果是:{}",res);
        //调用反射对象的getname方法[已经在反射方法了做了赋值操作]
        String name = infoReflect.getName();
        log.warn("调用反射对象的getname方法的结果是:{}",name);

    }


}
View Code

3.测试

运行测试类,控制台打印

16:16:40.811 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取传入原对象的类型:com.example.javabaisc.reflect.deme.Info
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 反射对象名字:com.example.javabaisc.reflect.deme.Info@78a2da20
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:java.lang.String
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:String
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:getName
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:int
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:int
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:getId
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:void
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:void
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:setName
16:16:40.814 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:java.lang.String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:java.lang.String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:java.lang.String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:dosomething
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:java.lang.String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:java.lang.String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:private
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:java.lang.String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:love
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法修饰符:public
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法1:void
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取返回参数类型,写法2:void
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取方法名字:setId
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法1:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法2:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取参数类型名字,写法3:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用getMethod获取指定的方法,但是仅能获取public修饰的方法
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的修饰符:public
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的返回类型:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的名子:dosomething
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的参数类型:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用privateMethod获取指定的方法,可以获取被保护的方法
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的修饰符:private
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的返回类型:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的名子:love
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 指定方法的参数类型:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 获取所有属性
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:private
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:int
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:id
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:private
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:name
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:public
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:String
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:publicParam
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
16:16:40.815 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用getField获取指定属性,但是仅能获取public修饰的属性
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:public
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:String
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:publicParam
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ------------------------------------------------------------
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 使用getDeclaredField获取指定属性,可以获取被保护的属性
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性修饰符:private
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 属性类型:int
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 字段名字:id
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 调用对象的方法
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 调用 原对象 的 getname方法 获取name值为:你大爷啊啊啊
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - 调用 反射对象 的 getname方法 获取name值为:你大爷啊啊啊
16:16:40.816 [main] WARN com.example.javabaisc.reflect.deme.DoReflect - ===================================================================
我是自定义方法,输入参数是=扫地啦
16:16:41.085 [main] WARN com.example.javabaisc.reflect.deme.RETest - 调用反射对象的方法的结果是:扫地啦===fd1cfc80-e653-4661-9f06-77780f363a5d
16:16:41.087 [main] WARN com.example.javabaisc.reflect.deme.RETest - 调用反射对象的getname方法的结果是:你大爷啊啊啊
View Code

猜你喜欢

转载自www.cnblogs.com/c2g5201314/p/13172767.html