Should we use clone or BeanUtils.copyProperties an

2019-01-22 03:29发布

问题:

By the looks of it - BeanUtils.copyProperties seems to create a clone of an object. If this is the case, and what with the concerns around implementing the Cloneable interface (Only immutable objects are new where as mutable objects have references copied) which is the best and why?

I yesterday implemented cloneable and then realised I had to provide my own modifications for non String/Primative elements. I was then informed about BeanUtils.copyProperties which I am now using. Both implementations seem to provide a similar functionality.

Thanks

回答1:

Josh Bloch provides some fairly good arguments (including the one you provided) asserting that Cloneable is fundamentally flawed, favoring a copy constructor instead. See here.

I haven't yet encountered a practical use case for copying an immutable object. You're copying objects for a specific reason, presumably to isolate some set of mutable objects into a single transaction for processing, guaranteeing nothing can alter them until that unit of processing is complete. If they're already immutable then a reference is as good as a copy.

BeanUtils.copyProperties is often a less intrusive way of copying without having to alter your classes to be supported, and it offers some unique flexibility in compositing objects.

That said, copyProperties is not always one-size-fits-all. You may at some point need to support objects containing types that have specialized constructors, but are still mutable. Your objects can support internal methods or constructors to work around those exceptions, or you can register specific types into some external tool for copying, but it can't reach some places that even clone() can. It's good, but still has limits.



回答2:

BeanUtils is more flexible than standard clone that simply copies field values from an object to another. The clone method copies the fields from beans of the same class, but BeanUtils can do that for 2 instances of different classes having the same attribute names.

For example let's suppose that you have a Bean A that have a field String date and a bean B that have the same field java.util.Date date. with BeanUtils you can copy the string value and convert it automatically to date using DateFormat.

I've used that to convert a SOAP object into Hibernate objects which do not have the same data types.



回答3:

I think you are looking for a deep copy. you can have the below method in a util class and use it for any kind of objct.

public static <T extends Serializable> T copy(T input) {
    ByteArrayOutputStream baos = null;
    ObjectOutputStream oos = null;
    ByteArrayInputStream bis = null;
    ObjectInputStream ois = null;
    try {
        baos = new ByteArrayOutputStream();
        oos = new ObjectOutputStream(baos);
        oos.writeObject(input);
        oos.flush();

        byte[] bytes = baos.toByteArray();
        bis = new ByteArrayInputStream(bytes);
        ois = new ObjectInputStream(bis);
        Object result = ois.readObject();
        return (T) result;
    } catch (IOException e) {
        throw new IllegalArgumentException("Object can't be copied", e);
    } catch (ClassNotFoundException e) {
        throw new IllegalArgumentException("Unable to reconstruct serialized object due to invalid class definition", e);
    } finally {
        closeQuietly(oos);
        closeQuietly(baos);
        closeQuietly(bis);
        closeQuietly(ois);
    }
}


回答4:

From your question I guess that you need deep copy of the object . If this is the case don't use clone method as it is already specified in oracle docs that it provides shallow copy of the associated object. And I don't have enough idea about BeanUtils.copyProperties API.
Given below is the short demo of deep copy. Here I am deep copying a primitive array. You can try this code with any type of object.

import java.io.*;
class ArrayDeepCopy 
{
    ByteArrayOutputStream baos;
    ByteArrayInputStream bins;
    public void saveState(Object obj)throws Exception //saving the stream of bytes of object to `ObjectOutputStream`.
    {
        baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(obj);
        oos.close();
    }
    public int[][] readState()throws Exception //reading the state back to object using `ObjectInputStream`
    {
        bins = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream oins = new ObjectInputStream(bins);
        Object obj = oins.readObject();
        oins.close();
        return (int[][])obj;
    }
    public static void main(String[] args) throws Exception
    {
        int arr[][]= {
                        {1,2,3},
                        {4,5,7}
                    };
        ArrayDeepCopy ars = new ArrayDeepCopy();
        System.out.println("Saving state...");
        ars.saveState(arr);
        System.out.println("State saved..");
        System.out.println("Retrieving state..");
        int j[][] = ars.readState();
        System.out.println("State retrieved..And the retrieved array is:");
        for (int i =0 ; i < j.length ; i++ )
        {
            for (int k = 0 ; k < j[i].length ; k++)
            {
                System.out.print(j[i][k]+"\t");
            }
            System.out.print("\n");
        }

    }
}


回答5:

clone creates a shallow copy of the object, the clone object is always of the same class as the original one. All fields, private or not are copied.

BeanUtils.copyProperties API Copy property values from the origin bean to the destination bean for all cases where the property names are the same.

As to me, these two concepts have little in common.



回答6:

Cloning is done by you. If the instance which you trying clone contains reference of another instance you have to write cloning code to that one too. What if the instances contains chain of references to other instances? So if you do cloning by yourself, there are chances that you might miss a small detail.

BeanUtils.copyProperties on otherhand take care of everything by itself. It reduces your effort.