Java--反射机制与使用

Java的反射机制可以说是让其能够具有容易移植的方便,也是Java语言的特点之一。

在反序列化调用链子中经常能看到反射的使用,今天就来学习一下:

 

反射的使用

 

这里写一个demo,正常调用这个Study类

package reflect;

public class Study {
    private int num;
    public int getNum(){
        return num;
    }

    public void setNum(int num){
        this.num = num;
    }

    public static void main(String[] args) throws Exception{
        Study study = new Study();
        study.setNum(21);
        System.out.println("Your age is ~"+study.getNum());
    }
}

 

运行结果当然就是,这我们可以理解成Java的"正"射调用

 

 

那么调用反射就需要使用到一些API,下面这两个类肯定是需要引用的

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

 

我学着写了一个ReUse类来对Study类进行反射调用

package reflect;

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

public class ReUse {

    public static void main(String[] args) throws Exception {

        //获取需要反射调用的类 对象实例
        Class my = Class.forName("reflect.Study");

        //通过my获取构造函数对象 studyConstructor
        Constructor studyConstructor = my.getConstructor();

        //studyConstructor来使用newInstance()方法来获取反射的对象
        Object studyObj = studyConstructor.newInstance();
        //下面这样写与上面等价
       // Study studyObj = (Study)studyConstructor.newInstance();

        //通过Study对象实例my获取反射调用的方法对象
        Method setNumMethod = my.getMethod("setNum", int.class);
        Method getNumMethod = my.getMethod("getNum");

        //执行
        setNumMethod.invoke(studyObj,21);
        int str = (int) getNumMethod.invoke(studyObj);
        System.out.println("Your age is ^"+str);



    }
}

 

简单来说使用过程就是:获取反射类的对象my-->通过该对象获取构造函数对象Constructor

-->然后在通过构造函数对象使用newInstance()方法来获取反射对象(这里也可以直接用my对象来获取,下面会说两种区别)


Method 对象就是通过my来获取对应的方法的,该对象调用invoke()方法传入反射对象和参数等就可以调用反射对象的内置方法了

 

获取反射中的Class对象

 

有三种方法可以获取:

1.class.forName()

上面demo所用的就是第一种方法,当知道反射类的全路径时可以用这种方法。

 

2.使用.class()方法

在编译前就知道该Class,什么意思 比如我这个ReUse和Study处在一个package下就可以直接使用,

是等价的

        //Class my = Class.forName("reflect.Study");
        Class my = Study.class;

 

3.使用类对象的getClass()方法

在我们有该Class的对象时候,可以调用该对象的getClass()方法来直接获取

Study study = new Study();
Class my = study.getClass();

 

 

通过反射类创建对象

也就是前面说到的可以用my或者是用构造函数Constructor对象来获取反射对象

第一种:

Object studyObj = my.newInstance();

第二种:

        //通过my获取构造函数对象 studyConstructor
        Constructor studyConstructor = my.getConstructor();

        //studyConstructor来使用newInstance()方法来获取反射的对象
        Object studyObj = studyConstructor.newInstance();

两者的区别就是通过 Constructor 对象创建类对象可以选择特定构造方法,而通过 Class 对象则只能使用默认的无参数构造方法.

 

通过反射获取类的属性、方法和构造器

 

通过Class对象的getDeclaredFields()可以获取包括私有属性的所有属性

        //获取反射类 属性 方法
        Field[] names = my.getDeclaredFields();
        for (Field field: names){
            System.out.println(field.getName());
        }

 

这里输出private的num

 

 

还有一种方法是getFields(),但是无法获取私有属性。

Field是一个类,位于java.lang.reflect包下。在Java反射中Field类描述的是类的属性信息。

可参考:Field用法

 

在用Method 创建对象获取反射方法时

受保护成员和私有成员,在分别使用Field、Method和Constructor对象来设置或获得字段、调用方法,或者创建和初始化类的新实例的时候,会执行访问检查。
当反射对象的accessible标志设为true时,则表示反射的对象在使用时应该取消Java语言访问检查。反之则检查。

由于JDK的安全检查耗时较多,所以通过setAccessible(true)的方式关闭安全检查来提升反射速度。

比如这里我把getNum()方法改成private

 

 

直接反射调用就会报错了

 

 

怎么办呢?把getMethod()改成用getDeclaredMethod()加上Declared,并设置setAccessi为true这样就能访问到

Private的方法了

 

 
posted @ 2021-12-27 10:57  Erichas  阅读(53)  评论(0编辑  收藏  举报