您的位置:

Java对象深拷贝

在Java编程中,对象拷贝是一个非常常见的操作。对象拷贝分为浅拷贝和深拷贝两种方式,浅拷贝只是拷贝了对象的引用,而深拷贝则是完全复制了一个新的对象,两者的区别对于一些复杂的数据结构来说非常重要。本文将从多个方面对Java对象深拷贝进行详细的阐述。

一、常见的Java对象深拷贝方式

Java对象深拷贝可以通过以下几种方式实现:

1. 通过Java序列化实现

public static  T deepClone(T obj) {
    T cloneObj = null;
    try {
        // 写入字节流
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ObjectOutputStream obs = new ObjectOutputStream(out);
        obs.writeObject(obj);
        obs.close();

        // 分配内存,写入原始对象,生成新对象
        ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(ios);
        // 返回生成的新对象
        cloneObj = T(ois.readObject());
        ois.close();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return cloneObj;
}

  

该方法将对象进行序列化并写入字节流,然后再从字节流中读取并反序列化生成一个新的对象,实现对象深拷贝。需要注意的是,被拷贝的对象必须实现Serializable接口。

2. 通过对象的clone()方法实现

在Java中,Object对象自带一个clone()方法,可以实现对象的拷贝功能,需要注意的是,被拷贝的对象必须实现Cloneable接口。

class Person implements Cloneable {
    private String name;
    private int age;
    private List interests;

    @Override
    public Person clone() {
        Person clone = null;
        try {
            clone = (Person) super.clone();
            clone.interests = new ArrayList<>();
            for (String interest : interests) {
                clone.interests.add(interest);
            }
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return clone;
    }
}

  

该方法覆盖了clone()方法,首先通过super.clone()方法生成一个新的Person对象,然后再对该对象的引用成员变量进行深拷贝生成一个新的List对象,最后返回生成的新对象。

二、通过第三方库实现Java对象深拷贝

1. Apache Commons Lang

Apache Commons Lang是一个非常流行的Java工具库,其中有一个类叫SerializationUtils,可以实现对象的深拷贝:

public static  T clone(T object) {
    return deserialize(serialize(object));
}

private static byte[] serialize(Object object) {
    if (object == null) {
        throw new IllegalArgumentException("The object must not be null");
    }
    ByteArrayOutputStream baos = new ByteArrayOutputStream(512);
    try {
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(object);
        oos.close();
    } catch (IOException e) {
        throw new IllegalArgumentException("Failed to serialize object of type: " + object.getClass(), e);
    }
    return baos.toByteArray();
}

private static 
    T deserialize(byte[] objectData) {
    if (objectData == null) {
        throw new IllegalArgumentException("The byte[] must not be null");
    }
    ByteArrayInputStream bais = new ByteArrayInputStream(objectData);
    try {
        ObjectInputStream ois = new ObjectInputStream(bais);
        try {
            @SuppressWarnings("unchecked")
            T readObject = (T) ois.readObject();
            ois.close();
            return readObject;
        } catch (ClassNotFoundException e) {
            throw new IllegalStateException("Failed to deserialize object", e);
        }
    } catch (IOException e) {
        throw new IllegalStateException("Failed to deserialize object", e);
    }
}

   
  

该方法与Java序列化实现方式类似,只是对其进行了封装和简化,同样需要注意被拷贝的对象必须实现Serializable接口。

2. Spring Framework

Spring Framework是一个非常流行的Java开发框架,其中有一个类叫ObjectUtils,可以实现对象的深拷贝:

public static  T deepClone(T source) {
    if (source == null) {
        return null;
    }
    Class clazz = source.getClass();
    if (ClassUtils.isAssignable(Cloneable.class, clazz)) {
        Method cloneMethod = ClassUtils.getPublicMethodIfPossible(clazz, "clone");
        if (cloneMethod != null) {
            ReflectionUtils.makeAccessible(cloneMethod);
            try {
                return (T) cloneMethod.invoke(source);
            } catch (IllegalAccessException | InvocationTargetException e) {
                throw new RuntimeException(e);
            }
        }
    }
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream oos = null;
    ObjectInputStream ois = null;
    try {
        oos = new ObjectOutputStream(out);
        oos.writeObject(source);
        oos.flush();
        ByteArrayInputStream in = new ByteArrayInputStream(out.toByteArray());
        ois = new ObjectInputStream(in);
        return (T) ois.readObject();
    } catch (IOException | ClassNotFoundException ex) {
        throw new IllegalArgumentException("Failed to deep clone object", ex);
    } finally {
        try {
            if (oos != null) {
                oos.close();
            }
            if (ois != null) {
                ois.close();
            }
        } catch (IOException ex) {
            // ignore
        }
    }
}

  

该方法对Java序列化实现方式进行了封装,同时还支持通过调用clone()方法实现深拷贝。

三、Java对象深拷贝的应用场景

Java对象深拷贝非常适用于需要对复杂数据结构进行拷贝的场景。例如,在开发游戏时,每个游戏对象都是非常复杂的,包含了很多成员变量,如果只进行浅拷贝,可能会导致拷贝后的对象与原对象共享同一个成员变量,造成互相影响,而深拷贝则可以避免这种问题。

在Android开发中,深拷贝也有一定应用。例如,Activity之间传递数据时,如果直接使用Intent的putExtra()方法,可能会导致数据对象的成员变量与原对象共享同一内存地址,造成数据混乱,而通过使用深拷贝可以避免这种问题。

总之,Java对象深拷贝是一个非常常见且重要的操作,需要根据实际场景选择合适的实现方式,以确保程序运行的正确性。