考虑下面的代码:

DummyBean dum = new DummyBean();
dum.setDummy("foo");
System.out.println(dum.getDummy()); // prints 'foo'

DummyBean dumtwo = dum;
System.out.println(dumtwo.getDummy()); // prints 'foo'

dum.setDummy("bar");
System.out.println(dumtwo.getDummy()); // prints 'bar' but it should print 'foo'

所以,我想把dumm复制到dum2,在不影响dum2的情况下改变dumm。但是上面的代码并没有这样做。当我改变了dumm中的一些东西,同样的变化也会发生在dum2中。

我想,当我说dumtwo = dum时,Java只复制了引用。那么,有没有办法创建一个新的dum副本并将其分配给dumtwo呢?


当前回答

为什么使用反射API没有答案?

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                field.set(clone, field.get(obj));
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

这真的很简单。

EDIT:通过递归包含子对象

private static Object cloneObject(Object obj){
        try{
            Object clone = obj.getClass().newInstance();
            for (Field field : obj.getClass().getDeclaredFields()) {
                field.setAccessible(true);
                if(field.get(obj) == null || Modifier.isFinal(field.getModifiers())){
                    continue;
                }
                if(field.getType().isPrimitive() || field.getType().equals(String.class)
                        || field.getType().getSuperclass().equals(Number.class)
                        || field.getType().equals(Boolean.class)){
                    field.set(clone, field.get(obj));
                }else{
                    Object childObj = field.get(obj);
                    if(childObj == obj){
                        field.set(clone, clone);
                    }else{
                        field.set(clone, cloneObject(field.get(obj)));
                    }
                }
            }
            return clone;
        }catch(Exception e){
            return null;
        }
    }

其他回答

这也有用。假设模型

class UserAccount{
   public int id;
   public String name;
}

第一次添加 编译'com.google.code.gson:gson:2.8.1'到你的应用>gradle & sync。然后

Gson gson = new Gson();
updateUser = gson.fromJson(gson.toJson(mUser),UserAccount.class);

您可以通过在访问修饰符后使用瞬态关键字来排除使用字段。

注意:这是不好的做法。也不建议使用克隆或JavaSerialization,它是缓慢和坏的。为最佳性能参考写复制构造函数。

类似的

class UserAccount{
        public int id;
        public String name;
        //empty constructor
        public UserAccount(){}
        //parameterize constructor
        public UserAccount(int id, String name) {
            this.id = id;
            this.name = name;
        }

        //copy constructor
        public UserAccount(UserAccount in){
            this(in.id,in.name);
        }
    }

90000次迭代的测试数据: Line UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class);耗时808毫秒

Line UserAccount clone = new UserAccount(aO);耗时小于1毫秒

结论:如果你的老板很疯狂,而你喜欢速度,那就用gson吧。如果您喜欢质量,请使用第二个复制构造函数。

你也可以在Android Studio中使用复制构造函数代码生成器插件。

要做到这一点,你必须以某种方式克隆对象。虽然Java有克隆机制,但如果没有必要就不要使用它。创建一个复制方法,为你做复制工作,然后做:

dumtwo = dum.copy();

这里有一些关于完成副本的不同技巧的建议。

class DB {
  private String dummy;

  public DB(DB one) {
    this.dummy = one.dummy; 
  }
}

您可以尝试实现Cloneable并使用clone()方法;但是,如果你使用clone方法,你应该——按照标准——总是覆盖Object的公共Object clone()方法。

这里有一个关于clone()的合理解释,如果你最终需要它…

这里:克隆(Java方法)