深拷贝与浅拷贝

  • identityHashCode永远返回根据对象物理内存地址产生的hash值
    比如new出来的String 他们的hash值一样但是identityHashCode不一样
  • 不可变类

不可变类是指这个类的实例一旦创建完成后,就不能改变其成员变量值,也就是不能改变对象的状态。
Java 中八个基本类型的包装类和 String 类都属于不可变类,而其他的大多数类都属于可变类。

  • 深拷贝

相当于创建了一个新的对象,只是这个对象的所有内容,都和被拷贝的对象一模一样而已,即两者的修改是隔离的,相互之间没有影响、完全独立

  • 浅拷贝

也是创建了一个对象,但是这个对象的某些内容(比如A)依然是被拷贝对象的,即通过这两个对象中任意一个修改A,两个对象的A都会受到影响

1.类的复制

1.1 clone() 浅拷贝

需要实现Cloneable 接口的clone()方法
类本身是新的,但成员变量类不是新的,修改一个另一个也会改变,也需要clone() 才能实现深拷贝,而String和Integer由于不可变性,实际是一个值,但是修改不会互相影响

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Banana implements Serializable,Cloneable {
    private Integer weight;
    private String taste;
    private Apple apple;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
@Data
@AllArgsConstructor
public class Apple implements Serializable,Cloneable {
    private Integer weight;
    private String color;
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}

 @Test
public void cloneTest() throws Exception{
     Banana source = new Banana(11,"bitter", new Apple(80,"green"));
     Banana target = (Banana)source.clone();
     Banana  targetOne =(Banana)source.clone();
     targetOne.setApple((Apple)source.getApple().clone());

     System.out.println("taste:"+System.identityHashCode(source.getTaste()));
     System.out.println("taste:"+System.identityHashCode(target.getTaste()));
     System.out.println("taste:"+System.identityHashCode(targetOne.getTaste()));

     System.out.println("apple:"+System.identityHashCode(source.getApple()));
     System.out.println("apple:"+System.identityHashCode(target.getApple()));
     System.out.println("apple:"+System.identityHashCode(targetOne.getApple()));

     source.setTaste("sweet");
     source.getApple().setColor("red");
     System.out.println(source);
     System.out.println(target);
     System.out.println(targetOne);
}

在这里插入图片描述

2.2 BeanUtils 浅拷贝

同上

  @Test
    public void   BeanUtilsTest() throws Exception{
       Banana source = new Banana(80,"bitter",new Apple(12,"aaa"));
        Banana copy = new Banana();
        BeanUtils.copyProperties(source,copy);

        System.out.println("body:"+System.identityHashCode(source));
        System.out.println("body:"+System.identityHashCode(copy));
        System.out.println("taste:"+System.identityHashCode(source.getTaste()));
        System.out.println("taste:"+System.identityHashCode(copy.getTaste()));
        System.out.println("apple:"+System.identityHashCode(source.getApple()));
        System.out.println("apple:"+System.identityHashCode(copy.getApple()));
        System.out.println("color:"+System.identityHashCode(source.getApple().getColor()));
        System.out.println("color:"+System.identityHashCode(copy.getApple().getColor()));

        source.setTaste("sweet");
        source.getApple().setColor("red");
        System.out.println(source);
        System.out.println(copy);
    }

在这里插入图片描述

2.3 序列化 深拷贝

只有这样才是不管包含什么变量都完全是新的不会互相影响

    @Test
    public void cloneSerializableTest() throws Exception{
               Banana source = new Banana(11,"bitter", new Apple(80,"green"));
        Banana target = deepCopy(source);

        System.out.println(System.identityHashCode(source));
        System.out.println(System.identityHashCode(target));

        System.out.println("Apple:"+System.identityHashCode(source.getApple()));
        System.out.println("Apple:"+System.identityHashCode(target.getApple()));
        source.setTaste("sweet");
        source.getApple().setColor("red");
        System.out.println(source);
        System.out.println(target);
    }


   public static <T> T deepCopy(T src) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream out = new ObjectOutputStream(byteOut);
        out.writeObject(src);

        ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
        ObjectInputStream in = new ObjectInputStream(byteIn);
        @SuppressWarnings("unchecked")
        T dest = (T) in.readObject();
        return dest;
    }

在这里插入图片描述

2.List的复制

另外可以注意到的是List本身的构造方法,循环复制,addAll,copy,ArrayList.clone(),甚至变成数组
都是只有壳是新的,里面的内容都是同一个

 @Test
    public void listObjectTest() throws Exception{
        Apple source1 = new Apple(10,"green");
        ArrayList<Apple> srcList= new ArrayList<>();
        srcList.add(source1);
        List<Apple> dest1List= new ArrayList<>();
        srcList.forEach(o->dest1List.add(o));
        ArrayList<Apple> dest2List =   (ArrayList<Apple>)srcList.clone();
        ArrayList<Apple> dest3List =   new ArrayList<>(srcList);
        Apple[] dest4List =  srcList.toArray(new Apple[srcList.size()]);


        System.out.println(System.identityHashCode(srcList.get(0)));
        System.out.println(System.identityHashCode(dest1List.get(0)));
        System.out.println(System.identityHashCode(dest2List.get(0)));
        System.out.println(System.identityHashCode(dest3List.get(0)));
        System.out.println(System.identityHashCode(dest4List[0]));
        source1.setColor("red");
        System.out.println(srcList);
        System.out.println(dest1List);
        System.out.println(dest2List);
        System.out.println(dest3List);
        System.out.println(dest4List[0]);

    }

在这里插入图片描述

参考:
浅拷贝和深拷贝(谈谈java中的clone)

java List复制:浅拷贝与深拷贝

不可变类(immutable)总结

String的不可变性及StringBuilder原理

Java学习之深拷贝浅拷贝及对象拷贝的两种思路

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值