实战中遇到的List的add方法【浅拷贝】和【深拷贝】问题
实战遇到问题重现:出现下面问题,怀疑是add方法浅拷贝造成的内存地址指向同一个的原因
结果:
测试类:
import com.zdft.purchase.until.ListCopyUtil; import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * @Description * @Author saq * @Date 2023/2/20 10:35 */ public class CopyTest { @Test public void test() { // 获取一批id List<Long> ids = new ArrayList<>(); ids.add(666L); ids.add(888L); UserInfo userInfo = new UserInfo(); userInfo.setId(0L); userInfo.setName("张三"); userInfo.setHobby("画画"); List<UserInfo> oneResult = new ArrayList<>(); oneResult.add(userInfo); oneResult.add(userInfo); for (int i = 0; i < ids.size(); i++) { Long id = ids.get(i); oneResult.get(i).setId(id); } System.out.println("第一种:【浅】拷贝"); oneResult.forEach(item -> System.out.println(item)); System.out.println("【浅】拷贝内存地址指向同一个"); System.out.println("\n==========================================分割线==========================================\n"); List<UserInfo> twoResult = new ArrayList<>(); twoResult.add(userInfo); // 注意:对对象进行深拷贝以后 twoResult.add(ListCopyUtil.deepCopy(userInfo)); for (int i = 0; i < ids.size(); i++) { Long id = ids.get(i); twoResult.get(i).setId(id); } System.out.println("第二种:【深】拷贝"); twoResult.forEach(item -> System.out.println(item)); System.out.println("【深】拷贝内存地址重新指向一个新的"); } }
实体类
import java.io.Serializable; /** * @Description * @Author saq * @Date 2023/2/20 10:36 */ @Data public class UserInfo implements Serializable { private Long id; private String name; private String hobby; }
以下是证明:浅拷贝内存地址指向同一个,深拷贝以后指向不同的内存地址
结果:
测试类
import org.junit.Test; import java.util.ArrayList; import java.util.List; /** * @Description 【浅拷贝】和【深拷贝】内存地址发生变化 * @Author saq * @Date 2023/2/20 10:35 */ public class CopyTest { @Test public void test() { UserInfo userInfo = new UserInfo(); userInfo.setId(0L); userInfo.setName("张三"); userInfo.setHobby("画画"); List<UserInfo> oneResult = new ArrayList<>(); oneResult.add(userInfo); oneResult.add(userInfo); System.out.println("第一种:【浅】拷贝"); oneResult.forEach(item -> System.out.println(item)); System.out.println("【浅】拷贝内存地址指向同一个"); System.out.println("\n==========================================分割线==========================================\n"); List<UserInfo> twoResult = new ArrayList<>(); twoResult.add(userInfo); // 注意:对对象进行深拷贝以后 twoResult.add(ListCopyUtil.deepCopy(userInfo)); System.out.println("第二种:【深】拷贝"); twoResult.forEach(item -> System.out.println(item)); System.out.println("【深】拷贝内存地址重新指向一个新的"); } }
工具类
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.Collections; import java.util.List; public class ListCopyUtil { /** * 对集合进行深拷贝 * 注意需要岁泛型类进行序列化(实现serializable) * * @param src * @param <T> * @return * @throws */ public static <T> List<T> deepCopy(List<T> src) { try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(byteOut); ) { outputStream.writeObject(src); try (ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream inputStream = new ObjectInputStream(byteIn); ) { return (List<T>) inputStream.readObject(); } } catch (Exception e) { e.printStackTrace(); } return Collections.emptyList(); } /** * 对对象进行深拷贝 * 注意需要岁泛型类进行序列化(实现serializable) * * @param src * @param <T> * @return */ public static <T> T deepCopy(T src) { try (ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream outputStream = new ObjectOutputStream(byteOut); ) { outputStream.writeObject(src); try (ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream inputStream = new ObjectInputStream(byteIn); ) { return (T) inputStream.readObject(); } } catch (Exception e) { e.printStackTrace(); } return null; } }
实体类
import java.io.Serializable; /** * @Description * @Author saq * @Date 2023/2/20 10:36 */ public class UserInfo implements Serializable { private Long id;private String name; private String hobby; public Long getId() { return id; } public void setId(Long id) { this.id = id; }public String getName() { return name; } public void setName(String name) { this.name = name; } public String getHobby() { return hobby; } public void setHobby(String hobby) { this.hobby = hobby; } }