一文快速理解Java反射(详细对比图)

反射在java中使用频率还是比较高的,比如JDK动态代理使用反射获取到目标类所有的接口列表。还有我们熟悉的JDBC获取驱动,Class.forName(“com.mysql.jdbc.Driver”)

定义

在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。

术语

RTTI(Run-Time Type Identification),通过运行时类型信息程序能够使用基类的指针或引用来检查这些指针或引用所指的对象的实际派生类型。

反射和非反射的差异

反射是在运行期间动态获取class文件进行读取其中的信息,而普通的RTTI(非反射)就是在编译器获取class文件信息并加入到类加载器中
获取类的加载时机的区别:
在这里插入图片描述
生成对象步骤的区别:
在这里插入图片描述

反射的基本使用

比如修改private final的属性值

			// 必须通过反射调用,获取PrismSettings类的disableEffects字段
			Field field = PrismSettings.class.getDeclaredField("disableEffects");
			// 获取修饰符字段对象
			Field modifiersField = Field.class.getDeclaredField("modifiers");
			// 设置可修改为true
			modifiersField.setAccessible(true);
			// 作用到disableEffects字段上,并修改原本final的修饰符为非final
			modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);
			field.set(null, true);

获取UserService对象中的userDao私有字段

		// 获取字段
        Field field = UserService.class.getDeclaredField("userDao");
        // 设置为可修改
        field.setAccessible(true);
        // 获取字段对象
        UserDao userDao = (UserDao) field.get(userService);

使用反射实现自定义注解

创建一个可以注解在方法上的注解

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyMethodAnnotation {

    String value() default "";
    
}

创建一个对象User使用方法注解并在visit()方法上添加注解@MyMethodAnnotation

public class User {

    private String username;
    private String password;

    public User(String username, String password) {
        this.username = username;
        this.password = password;
    }


    @MyMethodAnnotation(value = "我是value")
    public void visit(){

    }
}

通过扫描package,获取每个类下的方法并判断是否有注解

@Test
    public void test() throws ClassNotFoundException {

        // 获取此包下所有的类全限定名
        List<String> classNameList = ReflectUtils.doScanner("com.siqi.java.reflect");

        for (String className : classNameList) {
            Class<?> clazz = Class.forName(className);
            // 获取所有的方法
            Method[] methods = clazz.getMethods();
            for (Method method : methods) {
                if (method.isAnnotationPresent(MyMethodAnnotation.class)) {
                    // 获取方法上指定的注解
                    MyMethodAnnotation myMethodAnnotation = method.getAnnotation(MyMethodAnnotation.class);

                    System.out.println("方法上有@MyMethodAnnotation注解 = " + method.getName() +
                            // 获取注解中的value
                            "  value = " + myMethodAnnotation.value());

                }
            }
        }
    }

反射工具类,拥有扫描package的方法

public class ReflectUtils {


    /**
     * 获取所有要扫描的包的全限定名
     *
     * @param packageName
     */
    public static List<String> doScanner(String packageName) {

        List<String> classNameList = new ArrayList<>();

        //把所有的.替换成/
        URL url = ReflectUtils.class.getClassLoader().getResource(packageName.replaceAll("\\.", "/"));
        File dir = new File(url.getFile());
        for (File file : dir.listFiles()) {
            if (file.isDirectory()) {
                //递归读取包
                doScanner(packageName + "." + file.getName());
            } else {
                String className = packageName + "." + file.getName().replace(".class", "");
                classNameList.add(className);
            }
        }
        return classNameList;
    }
}

总结

除了自定义注解,我们还可以采用反射机制实现一个BeanUtils,可以将一个对象的相同属性赋值给另一个对象,实现对象的clone功能

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

我思知我在

原创不易,多多一键三连

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值