Java 有没有更好的方法可以在不使用反射的情况下从对象克隆值?

Java 有没有更好的方法可以在不使用反射的情况下从对象克隆值?,java,java-8,Java,Java 8,尝试有效地检查对象的新副本是否有任何不同的字段,如果有,则更新本地字段并记下。如果任何字段发生更改,那么我需要将对象持久化到数据库中。如果不需要,我不想打那个电话,因此是布尔值 如果不使用反射,我想不出更好的方法来实现这一点,但我不想在这里使用反射,因为这里缺乏编译器支持的安全性(会有对字段名的字符串引用),而且并非所有字段都是相同的类型(我有一些Java 8即时字段) 我真正想要避免的是,在修改字段时,必须记住在sync方法中添加或减去。显然,减法不是什么大不了的事,因为这个方法会失败,但是如

尝试有效地检查对象的新副本是否有任何不同的字段,如果有,则更新本地字段并记下。如果任何字段发生更改,那么我需要将对象持久化到数据库中。如果不需要,我不想打那个电话,因此是布尔值

如果不使用反射,我想不出更好的方法来实现这一点,但我不想在这里使用反射,因为这里缺乏编译器支持的安全性(会有对字段名的字符串引用),而且并非所有字段都是相同的类型(我有一些Java 8即时字段)

我真正想要避免的是,在修改字段时,必须记住在sync方法中添加或减去。显然,减法不是什么大不了的事,因为这个方法会失败,但是如果有人不记得更新新字段,那么加法是可怕的

public boolean syncWithFieldsFrom(User currentUser) {
    boolean doesUserNeedUpdating = false;
    if (!StringUtils.equals(email, currentUser.email)) {
        email = currentUser.email;
        doesUserNeedUpdating = true;
    }
    if (!StringUtils.equals(firstName, currentUser.firstName)) {
        firstName = currentUser.firstName;
        doesUserNeedUpdating = true;
    }
    if (!StringUtils.equals(lastName, currentUser.lastName)) {
        lastName = currentUser.lastName;
        doesUserNeedUpdating = true;
    }
    if (!StringUtils.equals(fullName, currentUser.fullName)) {
        fullName = currentUser.fullName;
        doesUserNeedUpdating = true;
    }
    return doesUserNeedUpdating;
}
对于深度克隆(克隆整个对象层次结构): commons lang SerializationUtils-使用序列化-如果所有类都在 控件,您可以强制实现可序列化

Java Deep Cloning Library - using reflection - in cases when the classes or the 
objects you want to clone are out of your control (a 3rd party library) and you can't 
make them implement Serializable, or in cases you don't want to implement Serializable.
对于浅层克隆(仅克隆第一级属性): 在大多数情况下,共同的小动物

 Spring BeanUtils - if you are already using spring and hence have this utility on 
 the classpath.

 I deliberately omitted the "do-it-yourself" option - the API's above provide a good 
 control over what to and what not to clone (for example using transient, or String[] 
 ignoreProperties), so reinventing the wheel isn't preferred.
请参考下面的网址。也许能帮你了解一些情况


这可能有点过分,但您可以使用lambdas提取字段并对其运行循环。为了简单起见,我假设您有getter和setter

private static class Field<T> {
    final Function<User, T> getter;
    final BiConsumer<User, T> setter;

    Field(Function<User, T> getter, BiConsumer<User, T> setter) {
        this.getter = getter;
        this.setter = setter;
    }

    boolean sync(User src, User dst) {
        T srcField = getter.apply(src);
        if (!Objects.equal(srcField, getter.apply(dst))) {
            setter.accept(dst, srcField);
            return true;
        }
        return false;
    }
}

private static final List<Field<?>> FIELDS = Arrays.asList(
        new Field<>(User::getEmail, User::setEmail),
        new Field<>(User::getFirstName, User::setFirstName),
        new Field<>(User::getLastName, User::setLastName),
        new Field<>(User::getFullName, User::setFullName));

public boolean syncWithFieldsFrom(User currentUser) {
    boolean updated = false;
    for (Field<?> f : FIELDS) {
        updated |= f.sync(currentUser, this);
    }
    return updated;
}
私有静态类字段{
最终功能吸气剂;
最终双消费者设定者;
字段(函数getter、双消费者setter){
this.getter=getter;
this.setter=setter;
}
布尔同步(用户src、用户dst){
T srcField=getter.apply(src);
如果(!Objects.equal(srcField,getter.apply(dst))){
setter.accept(dst,srcField);
返回true;
}
返回false;
}
}

私有静态最终列表另一种选择是使用代码生成工具,创建适当的代码来比较类的实例。例如,MapStruct使用它来生成类,这些类可以在运行时将对象映射到对象,而无需使用反射或序列化,而且性能非常好。它们总是字符串吗?在编译过程中更改生成脚本以生成此方法,问题就不存在了。@shmosel它们不都是字符串。:(看起来字段中的函数只获取字段,然后Objects.equals(f.apply(),f.apply(currentUser))以空安全的方式检查它们的相等性(awesome)。但我没有看到任何更新字段值的内容?哎呀,我完全错过了这一部分。您可以使用BiConsumer扩展示例,但它有点复杂。这让我比以前更接近:)我将对其进行修补。@Jazzepi我已使用setter支持进行了更新。它需要更多的样板文件,但扩展性很好。我将调用类
属性
,而不是
字段
,因为它是getter和setter的组合。它还降低了与现有类发生冲突的可能性。