Java反射机制开发经验总结

简介: 我在实际项目当中有经常用到反射机制,故而将学会的反射用法做一些汇总笔记,当做以后复盘所用。

我在实际项目当中有经常用到反射机制,故而将学会的反射用法做一些汇总笔记,当做以后复盘所用。

存在这样一个类:

package com.example.demo;
import com.alibaba.fastjson.annotation.JSONField;
public class User {
    private String name;
    @Value( value ="age_a")
    private String age;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
     public String getAge() {
        return age;
    }
    public void setAge(String age) {
        this.age = age;
    }
}


一、创建Class的三种方式

1 - Class clazz = Class.forName("com.example.demo.User");

注意一点,这里的forName("xxx")的类名需要全名,且为接口或类,否则加载不了。

2 - User user = new User();

Class clazz2 = user.getClass();

3 - Class clazz3 = User.class;

以上三种方式,都可以获取到类User的Class对象,通过Class,即可以开始玩反射了。


二、反射获取类的所有属性和属性类型

Class clazz = User.class;
Field[] fields = clazz.getDeclaredFields();
for (Field field : fields) {
    System.out.println("属性名:"+field.getName());
    System.out.println("属性的类型:"+field.getGenericType().getTypeName());
}

打印输出User的属性和属性类型——

属性名:name

属性的类型:java.lang.String

属性名:age

属性的类型:java.lang.String

利用反射获取到类的字段属性后,是不是可以利用反射来创建一个对象呢?答案是肯定的。

例如,可以类似下面代码,通过反射得到的字段属性,进而创建一个对象。

Map<String,Object> fileds = new HashMap<>();
fileds.put("name","张三");
fileds.put("age","10");
Object o = User.class.newInstance();
 Field[] fields = o.getClass().getDeclaredFields();
 for (Field field : fields) {
     //设置后可用反射访问访问私有变量
     field.setAccessible(true);
     //通过反射给属性赋值
     field.set(o,fileds.get(field.getName()));
 }
 User user1 = (User) o;
 System.out.println(user1.toString());

什么场景下可能需要这样做的呢?像一些内部数据与外部数据字段的映射,就可以通过类似的字段反射方式,将源数据映射给目标数据,进而得到可以插入数据库的目标对象。


三、反射动态修改类属性的注解值

注意一点,我们在设置User类时,对其中一个字段加了注解:@Value( value ="age_a")。这是一种设置值的注解,既然是设置值,是否还可以在代码运行过程中,根据不同情况来动态修改呢?

字段上的注解,其实都存放在一个memberValues属性里,这是一个map,可以这样来获取——

Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
    //设置后可用反射访问访问私有变量
    if ("age".equals(field.getName() )){
        field.setAccessible(true);
       //获取 annotation 这个代理实例所持有的 InvocationHandler
       InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));
       // 获取 InvocationHandler 的 memberValues 字段
        Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
        memberValues.setAccessible(true);
        Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
        System.out.println(values);
    }
}

debug打断点,可以看到——

这个Map<String,Object>存储的是该@注解里的所有属性值,这里,@Value只有一个value属性——

public @interface Value {
    String value();
}

若把它换成类似@JSONField(name="age_a"),把上边的代码稍微修改下,如:

Field[] fields = User.class.getDeclaredFields();
for (Field field : fields) {
    if ("age".equals(field.getName() )){
        field.setAccessible(true);
          InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(JSONField.class));
    ......
    }
}

@JSONField注解的内部属性有如下方式——

再运行刚刚的代码,可以看到,这里Map<String,Object>获取存储到的,便是这个注解里所有的属性与对应的属性值。

到了这一步,回到先前上边的问题,若要动态改变这个注解的值,怎么处理呢?

其实,很简单,只需要直接进行值设置就可以了,例如——

InvocationHandler invocationHandler = Proxy.getInvocationHandler(field.getAnnotation(Value.class));
Field memberValues = invocationHandler.getClass().getDeclaredField("memberValues");
memberValues.setAccessible(true);
Map<String, Object> values = (Map<String, Object>) memberValues.get(invocationHandler);
values.put("value","new_age");
memberValues.setAccessible(false);

只是,注意一点是,这里的key需要对应上注解里是属性值。


四、反射获取类的方法及调用方式

Object o=User.class.newInstance();
//通过反射获取到User的setAge方法,后面的String.class表示这个setAge方法的参数类型,若有多个,则按顺序列出
//同时,若为其他类型,如List,Long,则为List.class,Long.class
 Method m =  (Method) o.getClass().getMethod("setAge",String.class);
 m.invoke(o,"name");
 User user = (User) o;
 System.out.println(user);

打印可见,age已为name,说明setAge调用成功了。

这类使用场景,在代理当中出现比较多。

最后,通过反射实现一个Map转成对象的封装工具——

public Object MapToObject(Object object,Map<String, Object> map) throws IllegalAccessException {
        Class cla =  object.getClass();
        Field[] fields = cla.getDeclaredFields();
        for(Field field:fields){
            field.setAccessible(true);
            if("serialVersionUID".equals(field.getName()))continue;
            if(map.get(field.getName())!=null) {
                Object value=map.get(field.getName());
                value=convertValType(value,field.getType());
                field.set(object, value);
            }
        }
        return object;
    }
    private static Object convertValType(Object value, Class<?> fieldTypeClass) {
        Object o = null;
        if (Long.class.getName().equals(fieldTypeClass.getName())
                || long.class.getName().equals(fieldTypeClass.getName())) {
            o = Long.parseLong(value.toString());
        } else if (Integer.class.getName().equals(fieldTypeClass.getName())
                || int.class.getName().equals(fieldTypeClass.getName())) {
            o = Integer.parseInt(value.toString());
        } else if (Float.class.getName().equals(fieldTypeClass.getName())
                || float.class.getName().equals(fieldTypeClass.getName())) {
            o = Float.parseFloat(value.toString());
        } else if (Double.class.getName().equals(fieldTypeClass.getName())
                || double.class.getName().equals(fieldTypeClass.getName())) {
            o = Double.parseDouble(value.toString());
        } else {
            retVal = o;
        }
        return retVal;
    }


目录
相关文章
|
4天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
16 2
|
8天前
|
Java 编译器
探索Java中的异常处理机制
【10月更文挑战第35天】在Java的世界中,异常是程序运行过程中不可避免的一部分。本文将通过通俗易懂的语言和生动的比喻,带你了解Java中的异常处理机制,包括异常的类型、如何捕获和处理异常,以及如何在代码中有效地利用异常处理来提升程序的健壮性。让我们一起走进Java的异常世界,学习如何优雅地面对和解决问题吧!
|
19天前
|
XML 安全 Java
Java反射机制:解锁代码的无限可能
Java 反射(Reflection)是Java 的特征之一,它允许程序在运行时动态地访问和操作类的信息,包括类的属性、方法和构造函数。 反射机制能够使程序具备更大的灵活性和扩展性
33 5
Java反射机制:解锁代码的无限可能
|
9天前
|
SQL 安全 Java
安全问题已经成为软件开发中不可忽视的重要议题。对于使用Java语言开发的应用程序来说,安全性更是至关重要
在当今网络环境下,Java应用的安全性至关重要。本文深入探讨了Java安全编程的最佳实践,包括代码审查、输入验证、输出编码、访问控制和加密技术等,帮助开发者构建安全可靠的应用。通过掌握相关技术和工具,开发者可以有效防范安全威胁,确保应用的安全性。
22 4
|
7天前
|
Java 数据库连接 开发者
Java中的异常处理机制及其最佳实践####
在本文中,我们将探讨Java编程语言中的异常处理机制。通过深入分析try-catch语句、throws关键字以及自定义异常的创建与使用,我们旨在揭示如何有效地管理和响应程序运行中的错误和异常情况。此外,本文还将讨论一些最佳实践,以帮助开发者编写更加健壮和易于维护的代码。 ####
|
11天前
|
缓存 监控 Java
如何运用JAVA开发API接口?
本文详细介绍了如何使用Java开发API接口,涵盖创建、实现、测试和部署接口的关键步骤。同时,讨论了接口的安全性设计和设计原则,帮助开发者构建高效、安全、易于维护的API接口。
35 4
|
13天前
|
安全 IDE Java
Java反射Reflect机制详解
Java反射(Reflection)机制是Java语言的重要特性之一,允许程序在运行时动态地获取类的信息,并对类进行操作,如创建实例、调用方法、访问字段等。反射机制极大地提高了Java程序的灵活性和动态性,但也带来了性能和安全方面的挑战。本文将详细介绍Java反射机制的基本概念、常用操作、应用场景以及其优缺点。 ## 基本概念 ### 什么是反射 反射是一种在程序运行时动态获取类的信息,并对类进行操作的机制。通过反射,程序可以在运行时获得类的字段、方法、构造函数等信息,并可以动态调用方法、创建实例和访问字段。 ### 反射的核心类 Java反射机制主要由以下几个类和接口组成,这些类
31 2
|
16天前
|
SQL Java 程序员
倍增 Java 程序员的开发效率
应用计算困境:Java 作为主流开发语言,在数据处理方面存在复杂度高的问题,而 SQL 虽然简洁但受限于数据库架构。SPL(Structured Process Language)是一种纯 Java 开发的数据处理语言,结合了 Java 的架构灵活性和 SQL 的简洁性。SPL 提供简洁的语法、完善的计算能力、高效的 IDE、大数据支持、与 Java 应用无缝集成以及开放性和热切换特性,能够大幅提升开发效率和性能。
|
17天前
|
存储 Java 关系型数据库
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践
在Java开发中,数据库连接是应用与数据交互的关键环节。本文通过案例分析,深入探讨Java连接池的原理与最佳实践,包括连接创建、分配、复用和释放等操作,并通过电商应用实例展示了如何选择合适的连接池库(如HikariCP)和配置参数,实现高效、稳定的数据库连接管理。
34 2
|
18天前
|
存储 缓存 安全
🌟Java零基础:深入解析Java序列化机制
【10月更文挑战第20天】本文收录于「滚雪球学Java」专栏,专业攻坚指数级提升,希望能够助你一臂之力,帮你早日登顶实现财富自由🚀;同时,欢迎大家关注&&收藏&&订阅!持续更新中,up!up!up!!
22 3