[Java] 数组的深拷贝

看到一个认为用clone方法对多维数组(数组的数组)进行深拷贝的代码,然后忘记了数组的clone方法并不会进行元素的深拷贝,突然间就开始想,能否实现一个通用的多维数组的深拷贝(仅使用JDK 7附带的类库)呢?于是就开始摸索了一下,似乎可以使用反射实现,但实用性可能不强…顺便提一下,处理非Cloneable对象的方式有些马虎(含糊)。

(2019/5/8 追記)
我发现这篇旧的垃圾文章竟然被提名在这里,所以从实现示例的评论中删除了“引用传递”的表达(汗)

通过反思来执行

import java.lang.reflect.Array;
import java.lang.reflect.Method;

public class ArrayUtils {

    public static Object deepClone(Object original) {
        // 引数がnullもしくは非配列の場合はnullを返す
        if (original == null || !original.getClass().isArray()) {
            return null;
        }
        // 同期化
        synchronized (original) {
            // 配列の要素の型
            Class<?> componentType = original.getClass().getComponentType();
            // 配列の要素の数
            int length = Array.getLength(original);
            // 配列の複製(ガラ)を生成
            Object duplicate = Array.newInstance(componentType, length);
            try {
                // 配列の要素の数だけループ処理
                for (int i = 0; i < length; i++) {
                    Object item = Array.get(original, i);
                    if (item == null) {
                        // 要素がnullの場合
                        Array.set(duplicate, i, null);
                    }
                    else {
                        if (item.getClass().isArray()) {
                            // 要素が配列の場合は再帰処理開始
                            Object clone = deepClone(item);
                            Array.set(duplicate, i, componentType.cast(clone));
                        }
                        else {
                            //要素が配列ではない場合
                            Class<?> type = item.getClass();
                            if (type.cast(item) instanceof Cloneable) {
                                // Cloneableインターフェイスを実装していればcloneメソッドの戻り値を格納
                                Method clone = type.getMethod("clone");
                                Array.set(duplicate, i, type.cast(clone.invoke(item)));
                            }
                            else {
                                // Cloneableインターフェイスを実装していなければそのまま格納(ディープコピーできてないかも)
                                Array.set(duplicate, i, type.cast(item));
                            }
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            }
            return duplicate;
        }
    }

}

如果我们仅限制在可序列化的对象数组上,似乎可以使用以下实现。不过,性能可能会受到影响。

使用序列化和反序列化进行实现

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;

public class ArrayUtils {

    public static Object deepClone(Object original) {
        // 引数がnullもしくは非配列、シリアライズ不可の場合はnullを返す
        if (original == null || !original.getClass().isArray() || !isSerializable(original)) {
            return null;
        }
        // 同期化
        synchronized(original) {
            ByteArrayOutputStream baos = null;
            ObjectOutputStream oos = null;
            ByteArrayInputStream bais = null;
            ObjectInputStream ois = null;
            try {
                // シリアライズ・デシリアライズ
                baos = new ByteArrayOutputStream();
                oos = new ObjectOutputStream(baos);
                oos.writeObject(original);
                oos.flush();
                bais = new ByteArrayInputStream(baos.toByteArray());
                ois = new ObjectInputStream(bais);
                return ois.readObject();
            } catch (Exception e) {
                e.printStackTrace();
                return null;
            } finally {
                // クローズ処理
                if (ois != null) try { ois.close(); } catch (IOException ioe) {};
                if (bais != null) try { bais.close(); } catch (IOException ioe) {};
                if (oos != null) try { oos.close(); } catch (IOException ioe) {};
                if (baos != null) try { baos.close(); } catch (IOException ioe) {};
            }
        }
    }

    public static boolean isSerializable(Object target) {
        // 引数がnullもしくは非配列の場合はfalseを返す
        if (target == null || !target.getClass().isArray()) {
            return false;
        }
        // 配列の要素の型
        Class<?> componentType = target.getClass().getComponentType();
        // 配列の先頭の要素
        Object item = Array.get(target, 0);
        if (componentType.isArray()) {
            // 要素が配列の場合は再帰処理の結果を返す
            return isSerializable(item);
        }
        else {
            if (componentType.isPrimitive() || componentType.cast(item) instanceof Serializable) {
                // シリアライズ可
                return true;
            }
            else {
                // シリアライズ不可
                return false;
            }
        }
    }

}
广告
将在 10 秒后关闭
bannerAds