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

转载自:https://blog.csdn.net/qq_32828253/article/details/109266599?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522163974244416780265467568%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=163974244416780265467568&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_ecpm_v1~rank_v31_ecpm-2-109266599.pc_search_result_cache&utm_term=java%E5%8F%8D%E5%B0%84

定义


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

术语


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

反射和非反射的差异


反射是在运行期间动态获取class文件进行读取其中的信息,而普通的RTTI(非反射)就是在编译器获取class文件信息并加入到类加载器中
获取类的加载时机的区别:

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

生成对象步骤的区别:

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

反射的基本使用

比如修改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功能。

------本页内容已结束,喜欢请分享------

感谢您的来访,获取更多精彩文章请收藏本站。

© 版权声明
THE END
喜欢就支持一下吧
点赞5 分享
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片