java之反射机制

一、什么是反射

JAVA反射机制:

在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;

对于任意一个对象,都能够调用它的任意一个方法和属性;

(1)Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期 借助于ReflectionAPI取得任何类的内部信息,并能直接操作任意对象的内 部属性及方法。

 (2)加载完类之后,在堆内存的方法区中就产生了一个Class类型的对象(一个类只有一个Class对象),这个对象就包含了完整的类的结构信息。我们可以通过这个对象看到类的结构。这个对象就像一面镜子,透过这个镜子看到类的结构,所以,我们形象的称之为:反射。

 二、常用API

Class类:反射的核心类,反射所有的操作都是围绕该类来生成的,通过它,可以获取类的属性,方法等内容

Field类:表示类的属性,可以获取和设置类中属性的值

Method类:表示类的方法,它可以用来获取类中方法的信息,或者执行方法

Constructor类:表示类的构造方法


//获取包名、类名
clazz.getPackage().getName()//包名
clazz.getSimpleName()//类名
clazz.getName()//完整类名
 
//获取成员变量定义信息
getFields()//获取所有公开的成员变量,包括继承变量
getDeclaredFields()//获取本类定义的成员变量,包括私有,但不包括继承的变量
getField(变量名)
getDeclaredField(变量名)
 
//获取构造方法定义信息
getConstructor(参数类型列表)//获取公开的构造方法
getConstructors()//获取所有的公开的构造方法
getDeclaredConstructors()//获取所有的构造方法,包括私有
getDeclaredConstructor(int.class,String.class)
 
//获取方法定义信息
getMethods()//获取所有可见的方法,包括继承的方法
getMethod(方法名,参数类型列表)
getDeclaredMethods()//获取本类定义的的方法,包括私有,不包括继承的方法
getDeclaredMethod(方法名,int.class,String.class)
 
//反射新建实例
clazz.newInstance();//执行无参构造创建对象
clazz.newInstance(222,"吴彦祖");//执行有参构造创建对象
clazz.getConstructor(int.class,String.class)//获取构造方法
 
//反射调用成员变量
clazz.getDeclaredField(变量名);//获取变量
clazz.setAccessible(true);//使私有成员允许访问
f.set(实例,值);//为指定实例的变量赋值,静态变量,第一参数给null
f.get(实例);//访问指定实例变量的值,静态变量,第一参数给null
 
//反射调用成员方法
Method m = Clazz.getDeclaredMethod(方法名,参数类型列表);
m.setAccessible(true);//使私有方法允许被调用
m.invoke(实例,参数数据);//让指定实例来执行该方法

三、反射的应用

遍历某个类的所有的构造方法,属性,方法

案例:

StudentEntity类

public class StudentEntity {
    private String name;
    private Integer age;
    private String hobby;

    public StudentEntity(String name, Integer age) {
        System.out.println("有参构造方法1");
        this.name = name;
        this.age = age;

    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public String getHobby() {
        return hobby;
    }

    public void setHobby(String hobby) {
        this.hobby = hobby;
    }

    public StudentEntity(String name, Integer age, String hobby) {
        this.name = name;
        this.age = age;
        this.hobby = hobby;
        System.out.println("有参构造方法2");

    }
    public StudentEntity(){

        System.out.println("无参构造方法");
    }
    public void study(){
        System.out.println("正在学习。。。。。。");
    }
    public void sleep(){
        System.out.println("正在睡觉。。。。。");
    }
    public int count(){
        System.out.println("正在计算");
        return 0;
    }
    public void showInfo(){
        System.out.println("姓名:"+this.name +
                           " 年龄:"+this.age+
                           " 爱好:"+this.hobby);
    }
}

测试类:

public class Test {
    //遍历构造方法
    public void m1(Class clazz) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        //通过类名直接获取
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor con : constructors) {
            System.out.println(con);
        }
        System.out.println("---------------------------------");
    }
    //遍历属性
    public void m2(Class clazz){
        Field[] fields = clazz.getDeclaredFields();
        for (Field fie : fields) {
            System.out.println(fie.getName());
        }
        System.out.println("---------------------------------");
    }
    //遍历方法
    public void m3(Class clazz){
        Method[] declaredMethods = clazz.getDeclaredMethods();
        for (Method method : declaredMethods) {
            System.out.println(method);

        }
    }

    public static void main(String[] args) throws InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        Test01 test = new Test01();
        test.m1(StudentEntity.class);
        test.m2(StudentEntity.class);
        test.m3(StudentEntity.class);
    }
}

输出:

思路:

通过类的对象获取构造方法、定义的属性、定义的方法的集合,再通过集合去遍历

注意:对于私有属性遍历,首先要获取访问授权,使用以下语句

field.setAccessible(true);

通过文件名进行反射

案例:

写一个类ReflectUtil类, 类中写一个静态方法Object methodInvoker(String classMethd) 此classMethod为无参方法名如,

我们传入的实参字符串为:classMethod 为"java.lang.String.length()"就可以通过反射执行String类中的length方法、当传入的实参字符串为"com.atguigu.javase.reflect.Teacher.test()"就可以执行指定包下,指定类中的指定方法

public class ReflectUtil {
     public static Object  methodInvoker(String classMethd) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {

         int lastIndexOf = classMethd.lastIndexOf(".");
         String calssName = classMethd.substring(0,lastIndexOf);//获取类名
         //找到该类
         Class clazz = Class.forName(calssName);

         int index = classMethd.indexOf("(");

         //获取方法名
         String methodName = classMethd.substring(lastIndexOf+1,index);
         //实例化对象
        Object o = clazz.getDeclaredConstructor().newInstance();
         //找到该方法
        Method method = clazz.getMethod(methodName);
         //调用该方法
        return method.invoke(o);
     }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        methodInvoker("com.test.entity.StudentEntity.study()");
        //methodInvoker("java.lang.String.length()");

    }
}

输出 

思路:

通过最后一个" . " 获取类名,再通过类名找到该类,

通过" ( " 找到方法名,再通过方法名找到该方法

最后实例化该类对象(通过调用改类的构造函数实例化),并调用该方法

总结:

反射决定了一个程序员的上限,也就是说,反射学的好,程序员的格局也跟着大,反射是一种逆向的思维,当正面碰到编译问题过不去时,不妨试一试反射,在运行时去解决。api就这么多,需要灵活的去用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值