Reflect

反射Reflect

反射机制是干什么的

  • 可以在类加载的时候去获取类的相关信息(属性、方法、实现的接口、继承的类)
  • 反射可以通过字节码的方式来创建实例

反射在以后开发中的作用

​ 我们设计程序最终是要提高程序的执行效率,我们在开发一个模块的时候,要不停的去创建对象 User user = new User(); 使用new关键字,会使得程序之间产生耦合,以后new关键字使用多了,耦合就会变高,程序的执行效率就会很差

​ 这个时候我们能不能换一种方式去创建实例,尽量避免使用new关键字,反射机制就可以在不使用new的情况下去创建实例

​ 反射是各大java框架的底层:框架就是帮助程序解耦,提高程序的执行效率,提高开发人员的开发效率

spring 框架:容器

  • 通过java语言中的反射机制可以操作字节码文件
  • 通过反射机制可以操作代码片段
  • java.lang.reflect

什么是反射

​ 反射是java中比较偏底层的一种机制,通过反射可以在类加载时去获取类相关的信息

如何去获取一个类的字节码对象(Class)

对象.getClass()

类.class属性

Class.forName("全类名")

  • java.lang.Class:

    代表整个字节码,代表一个类型,代表整个

  • java.lang.reflect.Method

    代表字节码中的方法字节码,代表类中的方法

  • java.lang.reflect.Constructor:

    代表字节码中的构造方法字节码,代表类中的构造方法

  • java.lang.reflect.Field:

    代表字节码中的属性字节码,代表类中的成员变量(静态变量+实例变量)

获取类中的属性

获取类中公共的属性

getField()

//获取字节码对象
 Class stuClass = Class.forName("com.os467.pojo.Student");

 //getField()这个方法只能去获取公共的属性
 Field address = stuClass.getField("address");

 System.out.println(address);

获取类中所有的属性

getDeclaredField()

//getDeclaredField()这个方法可以去获取一个类中所有的属性
Field id = stuClass.getDeclaredField("id");

System.out.println(id);

getDeclaredFields()

//获取一个类中所有属性,封装成字节码数组
Field[] declaredFields = stuClass.getDeclaredFields();

获取全类名

String name = stuClass.getName();

获取简类名

String simpleName = stuClass.getSimpleName();

获取属性的类型

declaredField.getType()

获取属性的修饰符

//获取属性的修饰符代号
int modifiers = declaredField.getModifiers();

//将代号转成修饰符字符串
String string = Modifier.toSring(modifiers);

System.out.println(string);

在学习反射时,获取类的信息都是通过get方法去获取的

获取类中的方法

由于java类中的方法支持重载,所以在调用getMethod(方法名称,参数类型)方法时需要将方法的参数类型传入,不传入则默认获取无参的方法

获取类中公有的方法

public class ReflectDemo03 {

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

        //获取字节码对象
        Class stuClass = Student.class;

        //获取一个类中的方法
        Method setAge = stuClass.getMethod("setAge",Integer.class);

        System.out.println(setAge);

        Method study = stuClass.getMethod("study", int.class, double.class, String.class);

        System.out.println(study);

    }
}

获取类中所有的方法

public class ReflectDemo03 {

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

        //获取字节码对象
        Class stuClass = Student.class;

        //获取一个类中所有的方法
        Method[] declaredMethods = stuClass.getDeclaredMethods();

        for (Method declaredMethod : declaredMethods) {

            System.out.println(declaredMethod);

        }

    }
}

其它的方法

for (Method method : declaredMethods) {

    //获取方法名称
    System.out.println("方法名称"+method.getName());

    //获取方法返回值类型
    System.out.println("返回值类型"+method.getReturnType().getSimpleName());

    //获取方法的参数
    for (Class<?> parameterType : method.getParameterTypes()) {

        System.out.println("方法的参数类型"+parameterType);


    }

    //获取修饰符
    int modifiers = method.getModifiers();

    //将修饰符代号转成字符串
    String s = Modifier.toString(modifiers);

    System.out.println("修饰符"+s);

}

获取所有的构造

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


    //获取字节码对象
    Class aClass = Class.forName("com.os467.pojo.Student");

    //获取所有的构造
    Constructor[] declaredConstructors = aClass.getDeclaredConstructors();

    //遍历数组
    for (Constructor declaredConstructor : declaredConstructors) {

        System.out.println(declaredConstructor);

    }

}

反射工具类ReflectUtils

写一个工具类,写一个静态方法,方法传入一个类的全类名,然后反编译(可以获取这个类中所有的信息)这个类工具类要适用于所有的类

根据反射获取类的信息

  • 1、根据流对象先读取配置文件中的全类名数据
  • 2、根据全类名创建字节码对象
  • 3、根据字节码对象去获取类的信息,完成类的反编译
package com.os467.utils;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.Properties;

/**
 * 反编译工具类
 */
public class ReflectUtils {

    //构造私有化
    private ReflectUtils(){

    }

    /**
     * 根据反射获取类的信息
     * 1、根据流对象先读取配置文件中的全类名数据
     * 2、根据全类名创建字节码对象
     * 3、根据字节码对象去获取类的信息,完成类的反编译
     * @return
     */
    public static String getTypeMessageByReflect(){

        //用于字符串的追加,效率要比String高
        StringBuilder stringBuilder = new StringBuilder();

        try {

            //创建流对象
            FileReader fileReader = new FileReader("className.properties");

            //创建集合对象
            Properties properties = new Properties();

            //将配置文件中的数据装载到集合里面
            properties.load(fileReader);

            //根据全类名创建字节码对象
            Class aClass = Class.forName(properties.getProperty("className"));

            stringBuilder.append("public class ");
            stringBuilder.append(aClass.getSimpleName()+" { \n");
            //获取类中所有的属性
            Field[] declaredFields = aClass.getDeclaredFields();

            for (Field declaredField : declaredFields) {

                stringBuilder.append("\n\t");

                //获取属性的修饰符
                int modifiers = declaredField.getModifiers();

                //转成修饰符字符串
                String s = Modifier.toString(modifiers);

                //获取属性类型
                String simpleName = declaredField.getType().getSimpleName();

                //获取属性的名称
                String name = declaredField.getName();

                stringBuilder.append(s+" "+simpleName+" "+name+";");
                stringBuilder.append("\n");

            }

            //获取类的所有构造
            Constructor[] declaredConstructors = aClass.getDeclaredConstructors();

            //遍历数组
            for (Constructor declaredConstructor : declaredConstructors) {

                stringBuilder.append("\n\t");

                //获取构造的修饰符
                int modifiers = declaredConstructor.getModifiers();

                //转成修饰符字符串
                String s = Modifier.toString(modifiers);

                //获取构造名称
                String name = aClass.getSimpleName();

                stringBuilder.append(s + " " + name + "(");

                //获取参数列表
                Class[] parameterTypes = declaredConstructor.getParameterTypes();

                //遍历参数列表
                for (Class parameterType : parameterTypes) {

                    //获取参数名
                    stringBuilder.append(parameterType.getSimpleName()+",");

                }

                //判断有参的还是无参的
                if (parameterTypes.length > 0){

                    //删除具体下标下面的字符
                    stringBuilder.deleteCharAt(stringBuilder.length() - 1);

                }

                stringBuilder.append(") {}");

                stringBuilder.append("\n");

                //获取所有的普通方法
                Method[] declaredMethods = aClass.getDeclaredMethods();

                //遍历数组
                for (Method declaredMethod : declaredMethods) {

                    stringBuilder.append("\n\t");

                    //获取方法的修饰符
                    int modifiers1 = declaredMethod.getModifiers();

                    //转成修饰符字符串
                    String s1 = Modifier.toString(modifiers1);

                    //获取返回值类型
                    String simpleName = declaredMethod.getReturnType().getSimpleName();

                    stringBuilder.append(s1 + " " +simpleName + " " + declaredMethod.getName()+"(");

                    //获取普通方法的参数列表
                    Class[] parameterTypes1 = declaredMethod.getParameterTypes();

                    //遍历参数
                    for (Class parameterType : parameterTypes1) {

                        stringBuilder.append(parameterType.getSimpleName()+",");

                        if (parameterTypes.length > 0){

                            //删除最后一个逗号
                            stringBuilder.deleteCharAt(stringBuilder.length() - 1);

                        }

                    }
                    stringBuilder.append("){}");

                    stringBuilder.append("\n");

                }

            }

            stringBuilder.append("\n}");

        } catch (Exception e) {
            e.printStackTrace();
        }


        return stringBuilder.toString();
    }


}

反射

  • 通过反射机制访问对象的某个属性
  • 通过反射机制调用对象的某个方法
  • 通过反射机制调用某个构造方法实例化对象
  • 通过反射机制获取父类及父类型接口

获取父类

Class superclass = aClass.getSuperclass();

获取实现的接口

Class[] interfaces = aClass.getInterfaces();

如何通过反射机制来创建一个类的实例

无参构造实例

newInstance()

 //获取字节码对象
Class aClass = Student.class;

//如何通过反射机制来创建一个类的实例
//默认情况下调用的是无参构造
Object o = aClass.newInstance();

if (o instanceof Student){

    Student student = (Student)o;

    System.out.println(student);

}

有参构造实例

getDeclaredConstructor() 不传参数就是获取无参构造实例

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

    //创建字节码对象
    Class aClass = User.class;

    //获取构造字节码对象
    Constructor constructor = aClass.getDeclaredConstructor(String.class,String.class);

    Object obj02 = constructor.newInstance("root", "123456");

    System.out.println(obj02);
    
}

如何通过反射来给属性赋值

//获取属性,返回属性字节码对象
Field addressFiled = aClass.getDeclaredField("address");

//给属性进行一个赋值操作
//Object obj 属性所在类的实例
//Object value 具体要赋的值
addressFiled.set(o,"南京市");

//通过反射获取属性具体的值
System.out.println(addressFiled.get(o));

System.out.println(o);

如何通过反射获取属性值

方法一

先打破封装,再通过set方法给属性赋值

//获取属性字节码对象
Field declaredFieldName = aClass.getDeclaredField("name");

//打破封装
declaredFieldName.setAccessible(true);

//通过反射机制来创建一个类的实例
//采用的无参构造创建的实例
Object o = aClass.newInstance();

//调用set方法给属性赋值
declaredFieldName.set(o,"张三");

System.out.println(o);

方法二

通过反射调用这个属性所对应的set方法给属性赋值

通过反射调用类中的方法

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

    //获取字节码对象
    Class userClass = User.class;

    //获取方法字节码对象
    Method declaredMethod = userClass.getDeclaredMethod("login",String.class,String.class);

    //通过反射创建实例
    Object o = userClass.newInstance();

    //调用方法
    //通过反射调用方法的方法
    //Object var1 当前方法所在类的实例
    //Object... var2 你需要传的参数
    Object invoke = declaredMethod.invoke(o, "zs001", "123456");

    System.out.println(invoke);


}

注意:操作私有的方法需要打破封装

declaredMethod.setAccessible(true);

反射在以后的用途

反射最重要的用途就是开发各种通用框架,比如在spring中,我们将所有的类Bean交给spring容器管理,无论是XML配置Bean还是注解配置,当我们从容器中获取Bean来依赖注入时,容器会读取配置,而配置中给的就是类的信息,spring根据这些信息,需要创建那些Bean,spring就动态的创建这些类,还有在struts2的struts.xml中配置action,也是通过反射调用的action


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以邮件至 1300452403@qq.com

文章标题:Reflect

字数:2.5k

本文作者:Os467

发布时间:2022-07-13, 14:40:18

最后更新:2022-09-05, 00:09:07

原始链接:https://os467.github.io/2022/07/13/Reflect/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

×

喜欢就点赞,疼爱就打赏