33

見た目でBeanUtils.copyPropertiesは、オブジェクトのクローンを作成しているようです。この場合、Cloneable インターフェースの実装に関する懸念はどうなりますか (可変オブジェクトには参照がコピーされているため、不変オブジェクトのみが新しくなります)、どちらが最適で、その理由は何ですか?

昨日、クローン可能を実装しましたが、String/Primative 以外の要素に独自の変更を加える必要があることに気付きました。BeanUtils.copyPropertiesその後、私が現在使用しているものについて通知されました。どちらの実装も同様の機能を提供しているようです。

ありがとう

4

8 に答える 8

32

CloneableJosh Blochは、根本的に欠陥があると主張するかなり良い議論(あなたが提供したものを含む)を提供し、代わりにコピーコンストラクターを支持します。ここを参照してください。

不変オブジェクトをコピーするための実際のユースケースにはまだ遭遇していません。特定の理由でオブジェクトをコピーしています。おそらく、処理のために可変オブジェクトのセットを1つのトランザクションに分離し、その処理単位が完了するまでオブジェクトを変更できないことを保証します。それらがすでに不変である場合、参照はコピーと同じくらい優れています。

BeanUtils.copyProperties多くの場合、サポートするクラスを変更せずにコピーする際の邪魔にならない方法であり、オブジェクトの合成に独自の柔軟性を提供します。

とはいえ、copyProperties必ずしも万能ではありません。ある時点で、特殊なコンストラクターを持つタイプを含むオブジェクトをサポートする必要があるかもしれませんが、それでも変更可能です。オブジェクトは、これらの例外を回避するための内部メソッドまたはコンストラクターをサポートできます。または、特定の型をコピー用の外部ツールに登録できますが、到達できる場所に到達することはできませんclone()。良いですが、まだ限界があります。

于 2013-03-23T19:29:44.107 に答える
6

BeanUtils は、フィールド値をオブジェクトから別のオブジェクトに単純にコピーする標準のクローンよりも柔軟です。clone メソッドは同じクラスの Bean からフィールドをコピーしますが、BeanUtils は同じ属性名を持つ異なるクラスの 2 つのインスタンスに対してそれを行うことができます。

たとえば、フィールド String 日付を持つ Bean A と、同じフィールド java.util.Date 日付を持つ Bean B があるとします。BeanUtils を使用すると、文字列値をコピーして、DateFormat を使用して自動的に日付に変換できます。

これを使用して、SOAP オブジェクトを同じデータ型を持たない Hibernate オブジェクトに変換しました。

于 2013-03-24T09:51:10.970 に答える
3

ディープコピーを探していると思います。以下のメソッドを 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);
    }
}
于 2013-03-28T11:21:14.883 に答える
1

あなたの質問から、オブジェクトのディープ コピーが必要だと思います。この場合、関連付けられたオブジェクトの浅いコピーを提供するという点でclone既に指定されているため、メソッドを使用しないでください。そして、私はAPIについて十分な考えがありません。以下に、 の短いデモを示します。ここでは、 a をディープ コピーしています。このコードは、どのタイプのオブジェクトでも試すことができます。oracle docsBeanUtils.copyProperties
deep copyprimitive array

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");
        }

    }
}
于 2013-03-24T09:05:32.983 に答える
0

clone はオブジェクトのシャロー コピーを作成します。クローン オブジェクトは常に元のオブジェクトと同じクラスになります。プライベートかどうかに関係なく、すべてのフィールドがコピーされます。

BeanUtils.copyProperties APIプロパティ名が同じであるすべてのケースで、元の Bean から宛先 Bean にプロパティ値をコピーします。

私にとって、これら 2 つの概念にはほとんど共通点がありません。

于 2013-03-21T08:43:38.910 に答える
0

クローニングはあなたによって行われます。複製しようとしているインスタンスに別のインスタンスの参照が含まれている場合は、そのインスタンスにも複製コードを記述する必要があります。インスタンスに他のインスタンスへの参照チェーンが含まれている場合はどうなるでしょうか? そのため、自分でクローンを作成すると、細部を見逃す可能性があります。

一方、BeanUtils.copyProperties はすべてを単独で処理します。それはあなたの努力を減らします。

于 2013-03-28T09:07:11.620 に答える
0

任意のクラスのオブジェクトのディープ コピーの最適なソリューションは、オブジェクト内のオブジェクトを処理するための再帰があり、実際の G​​ET および SET 関数を使用してオブジェクトの整合性を維持することです。

私が提唱したい解決策は、ソース オブジェクトのすべての GET 関数を見つけて、それらをターゲット オブジェクトの SET 関数と一致させることです。ReturnType -> Parameter で一致する場合は、コピーを実行します。それらが一致しない場合は、それらの内部オブジェクトのディープ コピーを呼び出してみてください。

private void objectCopier(Object SourceObject, Object TargetObject) {
        // Get Class Objects of Source and Target
        Class<?> SourceClass = SourceObject.getClass();
        Class<?> TargetClass = TargetObject.getClass();
        // Get all Methods of Source Class
        Method[] sourceClassMethods = SourceClass.getDeclaredMethods();
        for(Method getter : sourceClassMethods) {
            String getterName = getter.getName();
            // Check if method is Getter
            if(getterName.substring(0,3).equals("get")){
                try {
                    // Call Setter of TargetClass with getter return as parameter
                    TargetClass.getMethod("set"+getterName.substring(3), getter.getReturnType()).invoke(TargetObject, getter.invoke(SourceObject));
                }catch(IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
                    try {
                        // Get Class of the type Setter in Target object is expecting
                        Class<?> SetTargetClass = TargetClass.getMethod(getterName).getReturnType();
                        // Create new object of Setter Parameter of Target
                        Object setTargetObject = SetTargetClass.newInstance();
                        // Copy properties of return object of the Source Object to Target Object
                        objectCopier(getter.invoke(SourceObject), setTargetObject);
                        // Set the copied object to the Target Object property
                        TargetClass.getMethod("set"+getterName.substring(3),SetTargetClass).invoke(TargetObject, setTargetObject);
                    } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException
                            | NoSuchMethodException | SecurityException | InstantiationException ef) {
                        System.out.println(getterName);
                    }
                }
            }
        }
    }
于 2021-10-11T01:11:32.850 に答える