Java使用PropertyDescriptor获取实体类中私有属性的值,并给私有属性赋值!

Java私有属性访问
本文介绍了一种利用PropertyDescriptor反射机制访问Java类私有属性的方法,适用于那些不提供getter和setter方法的情况。通过BeanUtils类实现了私有属性的读取和设置。

大家都知道Java类中的私有的(private)属性是获取不到的(即使使用继承依然获取不到),那如果非要获取私有属性的值怎么办呢?一般的做法是将该java类封装称为一个JavaBean,即封装该私有属性,提供一对共有的get,set方法来访问私有属性。一般情况下都会这样做!但遇到特殊情况呢?比如:访问一个Java类的私有属性,并且该类不提供访问该私有属性的共有方法!下面就为大家介绍一种方法访问java类的私有属性。

PropertyDescriptor(反射机制)类表示JavaBean类通过存储器方法导出一个属性。

public class PropertyDescriptor extends FeatureDescriptor  {  
    //构造方法  
    //通过调用 getFoo 和 setFoo 存取方法,为符合标准 Java 约定的属性构造一个 PropertyDescriptor  
    public PropertyDescriptor(String propertyName, Class<?> beanClass)  throws IntrospectionException{}  
  
    //获得属性的 Class 对象  
    public Class<?> getPropertyType(){}  
  
    //获得应该用于读取属性值的方法  
    public Method getReadMethod(){}  
  
    //获得应该用于写入属性值的方法  
    public Method getWriteMethod(){}  

 

下面看一段代码:

BeanUtils.java

package yw.javaben;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;

/**
 * 获取私有属性值JavaBean的帮助类
 * @author yw-tony
 *
 */
public class BeanUtils {
    private PropertyDescriptor dp = null;
    private String propertyName;
    private Object obj;
    /**
     * 构造方法
     * @param objName 属性名称
     * @param obj  要操作的对象
     */
    public BeanUtils(String objName,Object obj){
        try{
            this.propertyName = objName;
            this.obj = obj;
            dp = new PropertyDescriptor(propertyName, obj.getClass());
        }catch(Exception e){
            e.printStackTrace();
        }
    }
    /**
     * 获取javabean私有属性的值
     * @return
     * @throws Exception
     */
    public Object getProperty() throws Exception {
        //获取对象属性方法
        Method method = dp.getReadMethod();
        //获取属性对应的值
        Object retValue = method.invoke(obj);
        
        return retValue;
    }
    /**
     * 设置私有属性的值
     * @param setValue
     * @throws Exception
     */
    public void setProperty(Object setValue) throws Exception {
        Method method = dp.getWriteMethod();
        method.invoke(obj, setValue);
    }
    
    
}

BeanEntity.java

package yw.javaben;

/**
 * 验证属性标识符的javabean
 * @author yw-tony
 *
 */
public class BeanEntity {
    private int x;
    private int y = 10;
    public int getX() {
        return x;
    }
    public void setX(int x) {
        this.x = x;
    }
    public int getY() {
        return y;
    }
    public void setY(int y) {
        this.y = y;
    }
    

}

JavaBeanTest.java

public class JavaBeanTest {
    /**
     * 测试JavaBean
     * 
     * @param args
     */
    public static void main(String[] args) throws Exception {
        BeanEntity bean = new BeanEntity();
        String x = "x";//BeanEntity的属性名称
        BeanUtils utils = new BeanUtils(x, bean);
        utils.setProperty(12);
        Object value = utils.getProperty();
        System.out.println(value);

    }
}
<think>好的,用户问的是在Java中给POJO类的多个属性赋值时如何利用反射。首先,我需要理解反射的基本概念。反射允许程序在运行时检查类、方法、字段等信息,能动态调用方法和修改字段。这对于批量处理属性赋值很有用,特别是当属性很多的时候。 接下来,用户提到的是POJO类,也就是简单的Java对象,通常只有属性和getter、setter方法。所以,可能需要通过反射来获取这些setter方法,或者直接访问字段来设置。 首先,我应该考虑使用反射调用setter方法的方式。因为直接调用setter可能更符合封装的原则,而直接访问字段可能需要处理私有字段的访问权限问题。需要提醒用户注意setter方法的命名规范,比如setXxx,处理可能的异常,比如NoSuchMethodException。 然后,用户可能面临大量属性的情况,所以可能需要遍历属性名称和对应的,循环调用setter方法。这里需要获取方法的参数类型,使用Method的invoke方法来调用。同时,要考虑类型转换的问题,比如将字符串转换为目标属性的类型,如int、double等,否则会抛出IllegalArgumentException。 另外,如果用户的数据存储在Map中,比如键对的形式,可以遍历Map的entry,动态构造setter方法名,然后调用。这时候可能需要处理属性名的首字母大写的问题,比如将"name"转换为"setName"。 另一种方法是直接通过反射访问字段,这时候需要调用setAccessible(true)来覆盖访问权限,然后使用Field.set()方法赋值。但这种方式可能会破坏封装性,需要权衡利弊。 还需要提醒用户注意性能问题,反射操作通常比直接调用方法慢,特别是在大量使用时。如果性能要求高,可能需要考虑其他方案,比如预编译的代码生成工具(如Lombok的@Builder或MapStruct),或者使用Java Bean的PropertyDescriptor类来优化。 此外,异常处理也是关键。反射过程中可能会抛出多种异常,如IllegalAccessException、InvocationTargetException等,必须进行适当的捕获和处理,或者抛出更明确的异常信息,帮助调试。 最后,给出一个具体的示例代码会更有帮助。比如,如何通过反射调用setter方法,或者直接设置字段。示例中应该包括获取Class对象,遍历属性Map,构造方法名,处理参数类型,类型转换,调用方法等步骤。同时,要展示异常处理的部分,增强代码的健壮性。 总结来说,回答需要分步骤解释反射的基本用法,两种主要方法(调用setter和直接),注意事项(性能、异常、类型转换),以及可能的替代方案,帮助用户全面了解如何实现需求,做出合适的选择。</think>在Java中利用反射为POJO类大量属性赋值时,可以通过以下步骤实现: --- ### **一、反射基本原理** 反射机制通过`java.lang.reflect`包实现,主要涉及三个核心类: - `Class`:描述类的结构 - `Method`:操作方法 - `Field`:直接操作字段 --- ### **二、具体实现方式** #### **方式1:通过Setter方法赋值(推荐)** ```java public static void setProperties(Object obj, Map<String, Object> properties) { Class<?> clazz = obj.getClass(); properties.forEach((key, value) -> { try { // 构造setter方法名(需符合驼峰命名) String methodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1); Method method = clazz.getMethod(methodName, value.getClass()); method.invoke(obj, value); } catch (Exception e) { throw new RuntimeException("属性赋值失败: " + key, e); } }); } ``` #### **方式2:直接操作字段(需处理访问权限)** ```java public static void setFields(Object obj, Map<String, Object> properties) { Class<?> clazz = obj.getClass(); properties.forEach((key, value) -> { try { Field field = clazz.getDeclaredField(key); field.setAccessible(true); // 突破private限制 field.set(obj, value); } catch (Exception e) { throw new RuntimeException("字段赋值失败: " + key, e); } }); } ``` --- ### **三、使用示例** ```java // 定义POJO class User { private String name; private int age; // 必须包含setter方法(方式1需要) public void setName(String name) { this.name = name; } public void setAge(int age) { this.age = age; } } // 使用反射赋值 User user = new User(); Map<String, Object> props = new HashMap<>(); props.put("name", "张三"); props.put("age", 25); setProperties(user, props); // 方式1调用 // 或 setFields(user, props); // 方式2调用 ``` --- ### **四、关键注意事项** 1. **性能优化**: - 反射调用比常规方法慢约10-100倍 - 可缓存`Method`/`Field`对象提升性能 2. **类型匹配**: ```java // 处理不同类型转换(示例:字符串转int) if (field.getType() == int.class) { field.set(obj, Integer.parseInt((String)value)); } ``` 3. **安全限制**: - 需处理`IllegalAccessException` - 使用`setAccessible(true)`会绕过访问控制检查 --- ### **五、替代方案建议** 1. **Apache BeanUtils**: ```java BeanUtils.populate(obj, propertiesMap); ``` 2. **Spring BeanWrapper**: ```java BeanWrapper wrapper = new BeanWrapperImpl(obj); wrapper.setPropertyValues(propertiesMap); ``` 3. **Lombok Builder**(编译时生成代码,无反射开销): ```java User user = User.builder() .name("张三") .age(25) .build(); ``` --- ### **六、应用场景建议** - **适合场景**:动态配置加载、ORM框架实现、配置文件映射 - **避免场景**:高频调用的核心业务逻辑、对性能敏感的场景 通过合理使用反射机制,可以有效简化批量属性赋值的编码工作,但需权衡性能与灵活性的关系。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值