我们应该使用clone或BeanUtils.copyProperties以及原因

时间:2021-10-05 06:36:02

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?

通过它的外观 - BeanUtils.copyProperties似乎创建了一个对象的克隆。如果是这种情况,那么关于实现Cloneable接口的问题(只有不可变对象是新的,因为可变对象有复制的引用)这是最好的,为什么?

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.

我昨天实现了cloneable,然后意识到我必须为非String / Primative元素提供自己的修改。然后我被告知我正在使用的BeanUtils.copyProperties。这两种实现似乎都提供了类似的功能。

Thanks

谢谢

6 个解决方案

#1


20  

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.

Josh Bloch提供了一些相当不错的论据(包括你提供的论点)断言Cloneable从根本上是有缺陷的,而是支持复制构造函数。看这里。

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.

BeanUtils.copyProperties通常是一种不那么具有侵入性的复制方式,无需更改要支持的类,它在合成对象时提供了一些独特的灵活性。

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.

也就是说,copyProperties并不总是一刀切。您可能在某些时候需要支持包含具有专门构造函数但仍可变的类型的对象。您的对象可以支持内部方法或构造函数来解决这些异常,或者您可以将特定类型注册到某些外部工具进行复制,但它无法到达某些甚至是clone()的地方。这很好,但仍然有限制。

#2


4  

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.

BeanUtils比标准克隆更灵活,只需将字段值从对象复制到另一个对象。 clone方法从同一个类的bean复制字段,但BeanUtils可以为具有相同属性名称的不同类的2个实例执行此操作。

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.

例如,假设您有一个Bean A,它具有字段String date和一个具有相同字段java.util.Date日期的bean B.使用BeanUtils,您可以复制字符串值并使用DateFormat将其自动转换为日期。

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

我用它将SOAP对象转换为不具有相同数据类型的Hibernate对象。

#3


2  

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.

我想你正在寻找一份深刻的副本。您可以在util类中使用以下方法,并将其用于任何类型的对象。

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


1  

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.

从你的问题我想你需要对象的深层副本。如果是这种情况,请不要使用克隆方法,因为它已在oracle文档中指定它提供关联对象的浅表副本。我对BeanUtils.copyProperties API知之甚少。下面给出了深拷贝的简短演示。在这里,我正在深层复制一个原始数组。您可以使用任何类型的对象尝试此代码。

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


0  

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.

clone创建对象的浅表副本,clone对象始终与原始对象相同。所有字段,私有或非私有都被复制。

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

BeanUtils.copyProperties API将属性值从属bean复制到目标bean,以用于属性名称相同的所有情况。

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

对我来说,这两个概念没有什么共同之处。

#6


0  

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.

另一方面,BeanUtils.copyProperties可以自行处理所有事情。它减少了你的努力。

#1


20  

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.

Josh Bloch提供了一些相当不错的论据(包括你提供的论点)断言Cloneable从根本上是有缺陷的,而是支持复制构造函数。看这里。

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.

BeanUtils.copyProperties通常是一种不那么具有侵入性的复制方式,无需更改要支持的类,它在合成对象时提供了一些独特的灵活性。

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.

也就是说,copyProperties并不总是一刀切。您可能在某些时候需要支持包含具有专门构造函数但仍可变的类型的对象。您的对象可以支持内部方法或构造函数来解决这些异常,或者您可以将特定类型注册到某些外部工具进行复制,但它无法到达某些甚至是clone()的地方。这很好,但仍然有限制。

#2


4  

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.

BeanUtils比标准克隆更灵活,只需将字段值从对象复制到另一个对象。 clone方法从同一个类的bean复制字段,但BeanUtils可以为具有相同属性名称的不同类的2个实例执行此操作。

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.

例如,假设您有一个Bean A,它具有字段String date和一个具有相同字段java.util.Date日期的bean B.使用BeanUtils,您可以复制字符串值并使用DateFormat将其自动转换为日期。

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

我用它将SOAP对象转换为不具有相同数据类型的Hibernate对象。

#3


2  

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.

我想你正在寻找一份深刻的副本。您可以在util类中使用以下方法,并将其用于任何类型的对象。

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


1  

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.

从你的问题我想你需要对象的深层副本。如果是这种情况,请不要使用克隆方法,因为它已在oracle文档中指定它提供关联对象的浅表副本。我对BeanUtils.copyProperties API知之甚少。下面给出了深拷贝的简短演示。在这里,我正在深层复制一个原始数组。您可以使用任何类型的对象尝试此代码。

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


0  

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.

clone创建对象的浅表副本,clone对象始终与原始对象相同。所有字段,私有或非私有都被复制。

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

BeanUtils.copyProperties API将属性值从属bean复制到目标bean,以用于属性名称相同的所有情况。

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

对我来说,这两个概念没有什么共同之处。

#6


0  

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.

另一方面,BeanUtils.copyProperties可以自行处理所有事情。它减少了你的努力。