Java反射由浅入深

一、Java反射机制

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

二、通过反射获取类的信息

2.1、主方法

@Test
    void testPrintFields() throws ClassNotFoundException {
        /**
         * 1、获取并输出类的名称
         */
        //1.1获取Class
        Class<SonClass> sonClassClass = SonClass.class;
        System.out.println("类的全路径名称:" + sonClassClass.getName());
        //1.2获取Class
        Class<?> aClass = Class.forName("com.chenheng.juejin.reflection.SonClass");
        System.out.println("aClass->" + aClass);

        //1.3获取Class
        Class<? extends SonClass> bClass = new SonClass().getClass();
        System.out.println("bClass->" + bClass);
        /**
         * 2.1、获取所有public访问权限的变量
         */
        Field[] fields = sonClassClass.getFields();
        /**
         * 2.2、获取所有本类声明的变量(不管访问权限)
         */
        Field[] declaredFields = sonClassClass.getDeclaredFields();
        /**
         * 3.1、遍历public变量并输出变量信息(包括子类及父类的public属性信息)
         */
        for (Field field : fields) {
            //获取访问权限并输出
            int modifiers = field.getModifiers();
            System.out.println("field modifiers->" + Modifier.toString(modifiers));
            //输出变量的类型及变量名
            System.out.println("field type->" + field.getType().getName() + "->" + field.getName());
        }
        /**
         * 3.2、所有权限的字段信息(输出的是SonClass子类的所有权限的属性信息)
         */
        for (Field declaredField : declaredFields) {
            declaredField.setAccessible(true);
            //获取访问权限并输出
            int modifiers = declaredField.getModifiers();
            System.out.println("declaredField modifiers->" + Modifier.toString(modifiers));
            //输出变量的类型及变量名
            System.out.println("declaredField type->" + declaredField.getType().getName() + "->" + declaredField.getName());
        }
    }

2.2、其他类

2.2.1、FatherClass

public class FatherClass {
    public String mFatherName;
    public int mFatherAge;
    public void printFatherMsg(){}
}

2.2.2、SonClass

public class SonClass extends FatherClass{
    private String mSonName;
    protected int mSonAge;
    public String mSonBirthday;
    /**
     * 测试
     */
    public List<String> strList;

    public String getmSonName() {
        return mSonName;
    }

    public void setmSonName(String mSonName) {
        this.mSonName = mSonName;
    }

    public int getmSonAge() {
        return mSonAge;
    }

    public void setmSonAge(int mSonAge) {
        this.mSonAge = mSonAge;
    }
}

2.2.3、TestClass

public class TestClass {
    private String MSG = "Original";

    private final String FINAL_VALUE = "FINAL";

    private void privateMethod(String head , int tail){
        System.out.print("privateMethod->" + head + "->" + tail);
    }

    public String getMsg(){
        return MSG;
    }

    public String getFinalValue(){
        return FINAL_VALUE;
    }
}

三、通过反射获取类方法

3.1、类的公共方法

/**
     * 类的公共方法
     */
    @Test
    void testPrintMethods(){
        //1.获取并输出类的名称
        Class mClass = SonClass.class;
        System.out.println("类的名称:" + mClass.getName());

        //2.1 获取所有 public 访问权限的方法
        //包括自己声明和从父类继承的
        Method[] mMethods = mClass.getMethods();
        /**
         * 2.2 获取所有本类的的方法(不问访问权限)
         * 输出的都是 SonClass 类的方法,不问访问权限
         */
        Method[] declaredMethods = mClass.getDeclaredMethods();

        //3.遍历所有 public 访问权限的方法
        for (Method mMethod : mMethods) {
            /**
             * 方法权限,例如private、protected、public
             */
            int modifiers = mMethod.getModifiers();
            System.out.println("mMethods->" + Modifier.toString(modifiers));
            /**
             * 方法返回类型
             */
            Class<?> returnType = mMethod.getReturnType();
            System.out.println("returnType->" + returnType);
            /**
             * 方法入参,参数类型及参数名称
             */
            Class<?>[] parameterTypes = mMethod.getParameterTypes();
            System.out.println("parameterTypes->" + parameterTypes);
            for (Class<?> parameterType : parameterTypes) {
                System.out.println("getTypeName->" + parameterType.getTypeName() + "getName->" + parameterType.getName());
            }
            //获取并输出方法抛出的异常
            Class[] exceptionTypes = mMethod.getExceptionTypes();
            if (exceptionTypes.length == 0){
                System.out.println(" )");
            }
            else {
                for (Class c : exceptionTypes) {
                    System.out.println(" ) throws "
                            + c.getName());
                }
            }
        }
    }

3.2、访问私有方法

@Test
    void testPrivateMethod(){
        /**
         * 1.获取 Class 类实例
         */
        Class<TestClass> testClassClass = TestClass.class;
        try {
            //类对象,相当于TestClass testClassObject = new TestClass()
            TestClass testClassObject = testClassClass.newInstance();
            /**
             * 2.获取私有方法
             */
            Method privateMethod = testClassClass.getDeclaredMethod("privateMethod", String.class, int.class);
            /**
             * 通过反射调用方法
             */
            if (Objects.nonNull(privateMethod)) {
                //可以访问private的方法,只是获取访问权,并不是修改方法权限
                privateMethod.setAccessible(true);
                //第一个参数是类对象,第二个、第三个是参数
                privateMethod.invoke(testClassObject, "Java Reflect", 21);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

四、通过反射获取类字段

4.1、修改对象私有变量的值

@Test
    void modifyPrivateFiled(){
        //获取类
        Class<TestClass> testClassClass = TestClass.class;
        try {
            //获取类对象
            TestClass testClassObject = testClassClass.newInstance();
            /**
             * 获取public修饰的方法
             */
            //testClassClass.getField("")
            /**
             * 获取private修饰的方法
             */
            Field privateField = testClassClass.getDeclaredField("MSG");
            if (Objects.nonNull(privateField)) {
                //获取私有变量的访问权
                privateField.setAccessible(true);
                System.out.println("Before Modify:MSG = " + testClassObject.getMsg());
                /**
                 * 如果这个字段加final的话,这样无法修改字段值
                 * 否则是可以修改字段值
                 */
                privateField.set(testClassObject, "Modified");
                System.out.println("After Modify:MSG = " + testClassObject.getMsg());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

4.2、修改私有变量

class文件是在程序编译期生成的,编译时候程序实际还并未运行,所以不会牵扯到JVM。这里实际应该是由编译器优化的。

/**
     * 修改私有变量
     * JVM编译后会优化代码
     */
    @Test
    void modifyFinalFiled() throws Exception {
        /**
         * 1.获取 Class 类实例
         */
        Class<TestClass> testClassClass = TestClass.class;
        /**
         * 获取类对象
         */
        TestClass testClassObject = testClassClass.newInstance();
        /**
         * 2.获取私有常量
         */
        Field declaredField = testClassClass.getDeclaredField("FINAL_VALUE");
        /**
         * 3.修改常量的值
         */
        if (Objects.nonNull(declaredField)) {
            //获取私有常量的访问权
            declaredField.setAccessible(true);
            //通过反射输出 FINAL_VALUE 修改前的值
            System.out.println("Before Modify:FINAL_VALUE = "
                    + declaredField.get(testClassObject));
            //通过反射修改私有常量
            declaredField.set(testClassObject, "Modified");
            System.out.println("After Modify:FINAL_VALUE = "
                    + declaredField.get(testClassObject));
            //使用对象调用类的 getter 方法
            //获取值并输出
            System.out.println("Actually :FINAL_VALUE = "
                    + testClassObject.getFinalValue());
        }
    }

五、参考链接

1、Java 反射由浅入深 | 进阶必备
2、反射机制系列教材

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值