如何在java中复制对象?

jtjikinw  于 2021-06-26  发布在  Java
关注(0)|答案(23)|浏览(524)

考虑以下代码:

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'

所以,我想复制 dumdumtwo 和改变 dum 不影响 dumtwo . 但上面的代码并没有这样做。当我换衣服的时候 dum ,同样的变化也在发生 dumtwo 也。
我想,当我说 dumtwo = dum ,java只复制引用。那么,有没有办法创造一个新的 dum 并分配给 dumtwo ?

cxfofazt

cxfofazt1#

替代egaga的复制构造函数方法。您可能已经有了pojo,所以只需添加另一个方法 copy() 返回初始化对象的副本。

class DummyBean {
    private String dummyStr;
    private int dummyInt;

    public DummyBean(String dummyStr, int dummyInt) {
        this.dummyStr = dummyStr;
        this.dummyInt = dummyInt;
    }

    public DummyBean copy() {
        return new DummyBean(dummyStr, dummyInt);
    }

    //... Getters & Setters
}

如果你已经有了 DummyBean 想要一份副本:

DummyBean bean1 = new DummyBean("peet", 2);
DummyBean bean2 = bean1.copy(); // <-- Create copy of bean1 

System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());

//Change bean1
bean1.setDummyStr("koos");
bean1.setDummyInt(88);

System.out.println("bean1: " + bean1.getDummyStr() + " " + bean1.getDummyInt());
System.out.println("bean2: " + bean2.getDummyStr() + " " + bean2.getDummyInt());

输出:

bean1: peet 2
bean2: peet 2

bean1: koos 88
bean2: peet 2

但这两种方法都很有效,最终取决于你。。。

5kgi1eie

5kgi1eie2#

除了显式复制之外,另一种方法是使对象不可变(不是 set 或其他变异方法)。这样问题就永远不会出现。对于较大的对象来说,不变性变得更加困难,但另一方面,它将您推向分裂成连贯的小对象和复合对象的方向。

dwbf0jvd

dwbf0jvd3#

为什么使用反射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;
        }
    }

其实很简单。
编辑:通过递归包含子对象

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;
        }
    }
20jt8wwn

20jt8wwn4#

传递要复制的对象并获取所需的对象:

private Object copyObject(Object objSource) {
        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            oos.writeObject(objSource);
            oos.flush();
            oos.close();
            bos.close();
            byte[] byteData = bos.toByteArray();
            ByteArrayInputStream bais = new ByteArrayInputStream(byteData);
            try {
                objDest = new ObjectInputStream(bais).readObject();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        return objDest;

    }

现在分析 objDest 到所需对象。
快乐的编码!

vfh0ocws

vfh0ocws5#

如果可以将注解添加到源文件中,则可以使用这样的注解处理器或代码生成器。

import net.zerobuilder.BeanBuilder

@BeanBuilder
public class DummyBean { 
  // bean stuff
}

一个班级 DummyBeanBuilders 将生成一个静态方法 dummyBeanUpdater 创建浅拷贝的方法与手动创建的方法相同。

DummyBean bean = new DummyBean();
// Call some setters ...
// Now make a copy
DummyBean copy = DummyBeanBuilders.dummyBeanUpdater(bean).done();
iyfamqjs

iyfamqjs6#

您可以使用xstream从http://x-stream.github.io/:
xstream是一个简单的库,可以将对象序列化为xml,然后再序列化回来。
将其添加到项目中(如果使用maven)

<dependency>
    <groupId>com.thoughtworks.xstream</groupId>
    <artifactId>xstream</artifactId>
    <version>1.3.1</version>                
</dependency>

然后

DummyBean dum = new DummyBean();
dum.setDummy("foo");
DummyBean dumCopy = (DummyBean) XSTREAM.fromXML(XSTREAM.toXML(dum));

有了它,您就拥有了一个拷贝,而不需要实现任何克隆接口。

xoshrz7s

xoshrz7s7#

使用深度克隆实用程序:

SomeObjectType copy = new Cloner().deepClone(someObject);

这将深度复制任何java对象,请访问https://github.com/kostaskougios/cloning

6yjfywim

6yjfywim8#

你可以尝试实现 Cloneable 使用 clone() 方法;但是,如果您使用克隆方法,那么按照标准,您应该始终重写 Objectpublic Object clone() 方法。

zlhcx6iw

zlhcx6iw9#

为此,必须以某种方式克隆对象。尽管java有克隆机制,但如果不需要的话就不要使用它。创建一个复制方法来为您执行复制操作,然后执行以下操作:

dumtwo = dum.copy();

下面是一些关于完成拷贝的不同技巧的建议。

iyfamqjs

iyfamqjs10#

在包裹里 import org.apache.commons.lang.SerializationUtils; 有一种方法:

SerializationUtils.clone(Object);

例子:

this.myObjectCloned = SerializationUtils.clone(this.object);
s4chpxco

s4chpxco11#

这也行。假设模型

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

第一次添加 compile 'com.google.code.gson:gson:2.8.1' 到你的应用程序>渐变和同步。然后

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

可以通过使用 transient 关键字后的访问修饰符。
注意:这是不好的做法。也不建议使用 Cloneable 或者 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次迭代的测试统计:
线路 UserAccount clone = gson.fromJson(gson.toJson(aO), UserAccount.class); 需要808毫秒
线路 UserAccount clone = new UserAccount(aO); 不到1毫秒
结论:如果你的老板很疯狂,而你更喜欢速度,就用gson。如果您喜欢质量,请使用第二个复制构造函数。
你也可以在androidstudio中使用复制构造函数代码生成器插件。

ia2d9nvy

ia2d9nvy12#

对。你需要深度复制你的对象。

m0rkklqb

m0rkklqb13#

是的,您只是在引用对象。如果对象实现了 Cloneable .
查看这篇关于复制对象的wiki文章。
请参阅:对象复制

djp7away

djp7away14#

class DB {
  private String dummy;

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

7fhtutme15#

深度克隆是你的答案,它需要实现 Cloneable 接口和重写 clone() 方法。

public class DummyBean implements Cloneable {

   private String dummy;

   public void setDummy(String dummy) {
      this.dummy = dummy;
   }

   public String getDummy() {
      return dummy;
   }

   @Override
   public Object clone() throws CloneNotSupportedException {
      DummyBean cloned = (DummyBean)super.clone();
      cloned.setDummy(cloned.getDummy());
      // the above is applicable in case of primitive member types like String 
      // however, in case of non primitive types
      // cloned.setNonPrimitiveType(cloned.getNonPrimitiveType().clone());
      return cloned;
   }
}

你会这样称呼它 DummyBean dumtwo = dum.clone();

相关问题