当前位置:  开发笔记 > 编程语言 > 正文

用Java复制对象

如何解决《用Java复制对象》经验,为你挑选了4个好方法。

我有一个需要用Java复制的对象.我需要创建一个副本并在其上运行一些测试而不更改原始对象本身.

我假设我需要使用clone()方法,但这是受保护的.在网上做了一些研究之后,我可以看到这可以用我班上的公共方法覆盖.但我找不到如何做到这一点的解释.怎么可以这样做?

此外,这是实现我需要的最佳方式吗?



1> ecleel..:

使用Copy Constructor的另一个选项(来自Java Practices):

public final class Galaxy {

    public Galaxy (double aMass, String aName) {
        fMass = aMass;
        fName = aName;
    }

    /**
    * Copy constructor.
    */
    public Galaxy(Galaxy aGalaxy) {
        this(aGalaxy.getMass(), aGalaxy.getName());
        //no defensive copies are created here, since 
        //there are no mutable object fields (String is immutable)
    }

    /**
    * Alternative style for a copy constructor, using a static newInstance
    * method.
    */
    public static Galaxy newInstance(Galaxy aGalaxy) {
        return new Galaxy(aGalaxy.getMass(), aGalaxy.getName());
    }

    public double getMass() {
        return fMass;
    }

    /**
    * This is the only method which changes the state of a Galaxy
    * object. If this method were removed, then a copy constructor
    * would not be provided either, since immutable objects do not
    * need a copy constructor.
    */
    public void setMass( double aMass ){
        fMass = aMass;
    }

    public String getName() {
        return fName;
    }

    // PRIVATE /////
    private double fMass;
    private final String fName;

    /**
    * Test harness.
    */
    public static void main (String... aArguments){
        Galaxy m101 = new Galaxy(15.0, "M101");

        Galaxy m101CopyOne = new Galaxy(m101);
        m101CopyOne.setMass(25.0);
        System.out.println("M101 mass: " + m101.getMass());
        System.out.println("M101Copy mass: " + m101CopyOne.getMass());

        Galaxy m101CopyTwo = Galaxy.newInstance(m101);
        m101CopyTwo.setMass(35.0);
        System.out.println("M101 mass: " + m101.getMass());
        System.out.println("M101CopyTwo mass: " + m101CopyTwo.getMass());
    }
} 


我不会在复制构造函数中使用getter.首先,您不需要它们,因为您始终可以访问实例变量.其次,如果你自己做一个练习,你可以通过创建太多的getter来降低封装.最后它可能容易出错.想象一下,你调整getMass()中的值,而不是将调整后的值复制到新对象的实例变量中,如果在新对象上调用getMass,它将再次调整该值.

2> Ronald Blasc..:

有两种流行的方法.一个是提供clone你提到的方法,就像这样.

public class C implements Cloneable {
    @Override public C clone() {
        try {
            final C result = (C) super.clone();
            // copy fields that need to be copied here!
            return result;
        } catch (final CloneNotSupportedException ex) {
            throw new AssertionError();
        }
}

注意"复制字段......在这里!" 部分.初始result只是一个浅拷贝,这意味着如果有一个对象的引用,原始和result将共享同一个对象.例如,如果C包含,private int[] data您可能想要复制它.

...
final C result = (C) super.clone();
result.data = data.clone();
return result;
...

请注意,您不需要复制原始字段,因为它们的内容已被复制,或者不可变对象,因为它们无论如何都无法更改.

第二种方法是提供复制构造函数.

public class C {
    public C(final C c) {
        // initialize this with c
    }
}

或者是复印厂.

public class C {
    public static C newInstance(final C c) {
        return new C(c);
    }

    private C(final C c) {
        // initialize this with c
    }
}

两种方法都有各自的属性. clone很好,因为它是一个方法,所以你不必知道确切的类型.最后,你应该总是得到一个"完美"的副本.复制构造函数很好,因为调用者有机会决定,Java Collections可以看到.

final List c = ... 
// Got c from somewhere else, could be anything.
// Maybe too slow for what we're trying to do?

final List myC = new ArrayList(c);
// myC is an ArrayList, with known properties

我建议选择哪种方法,哪一种更适合你.

我只在单元测试中使用其他方法,如反射复制或立即序列化/反序列化.对我来说,他们觉得不太适合生产代码,主要是因为性能问题.



3> Yoni Roit..:

一些选择:

您可以Cloneable为您的对象实现并将clone()方法设置为公共.请参阅此处的完整说明:http://www.cafeaulait.org/course/week4/46.html
但是,这会生成浅层副本,可能不是您想要的.

您可以序列化和反序列化您的对象.您需要Serializable为对象及其所有字段实现接口.

您可以使用XStreamXML来执行序列化 - 您不必在此处实现任何内容.



4> Gareth Davis..:

对于测试代码序列化可能是最安全的答案,特别是如果对象已经是Serializable,请尝试使用Apache Commons SerializationUtils进行实现.

推荐阅读
小白也坚强_177
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有