field.set的多方面应用

发布时间:2023-05-20

一、基本介绍

field.set 方法是 Java 里一个核心的反射工具,用于将指定对象的成员变量的值设置为指定的值,例如:

Field field = object.getClass().getField("fieldName");
field.set(object, value);

其中,field 是通过反射获取的对象的成员变量,object 是要设置值的对象实例,value 是要设置的值。使用 field.set 方法可以避免破坏封装性,直接设置一个私有成员变量的值。

二、应用场景

1、模板方法模式中的反射调用

在模板方法模式中,父类定义了一个模板方法,其中定义了子类要实现的抽象方法。具体实现则由子类实现。为了不破坏封装性,在父类中定义了一些私有成员变量或方法,这些成员变量和方法可以被子类继承和调用。在使用的过程中,需要使用反射来调用这些私有成员变量和方法,可以使用 field.set 方法来设置这些私有成员变量的值。

public abstract class AbstractTemplate {
    private String name;
    public final void doSomeThing() {
        doBefore();
        doExecute();
        doAfter();
    }
    private void doBefore() {
        // some logic
    }
    protected abstract void doExecute();
    private void doAfter() {
        // some logic
    }
    public AbstractTemplate setName(String name) {
        try {
            Field field = this.getClass().getSuperclass().getDeclaredField("name");
            field.setAccessible(true);
            field.set(this, name);
        } catch (Exception e) {
            // handle exception
        }
        return this;
    }
}
public class ConcreteTemplate extends AbstractTemplate {
    @Override
    protected void doExecute() {
        // do something
    }
}

2、ORM框架中的映射

ORM 框架通过对象关系映射的方式将 Java 对象映射到数据库中的表中。在映射过程中,需要将 Java 对象中的成员变量映射到数据库表的列中。这些成员变量包括私有成员变量,为了避免破坏封装性,需要使用 field.set 方法设置这些私有成员变量的值。

public class User {
    private Long id;
    private String username;
    private String password;
    // getters and setters
}
public class UserDao {
    public void save(User user) {
        try {
            Field idField = user.getClass().getDeclaredField("id");
            Field usernameField = user.getClass().getDeclaredField("username");
            Field passwordField = user.getClass().getDeclaredField("password");
            idField.setAccessible(true);
            usernameField.setAccessible(true);
            passwordField.setAccessible(true);
            Long id = (Long) idField.get(user);
            String username = (String) usernameField.get(user);
            String password = (String) passwordField.get(user);
            // some logic to persist user to database
        } catch (Exception e) {
            // handle exception
        }
    }
}

三、注意事项

1、权限

由于 field.set 方法可以设置对象中的私有成员变量的值,因此需要使用 setAccessible(true) 开启权限,否则会抛出 IllegalAccessException 异常。

2、类型转换

在使用 field.set 方法时,需要注意设置的值和成员变量的类型一致,否则会出现类型转换异常。

3、性能

使用 field.set 方法比直接访问成员变量的性能要低,因为需要进行反射操作,建议在必要的情况下使用。