专业的JAVA编程教程与资源

网站首页 > java教程 正文

BeanUtils工具类中的copyProperties方法是深拷贝还是浅拷贝?

temp10 2024-10-19 14:55:46 java教程 15 ℃ 0 评论

关于深克隆和浅克隆:

根据结果,克隆分两种:(对于基本数据类型的属性,不考虑深或者浅拷贝)

  • 深克隆:引用类型属性也克隆
  • 浅克隆:引用类型属性不克隆

对象实现克隆的必要条件

对于clone()方法:要使对象实现克隆,需要让对象实体类实现Cloneable接口(它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常)。

BeanUtils工具类中的copyProperties方法是深拷贝还是浅拷贝?

clone() 是 Object 方法,通过该方法克隆一个一模一样的对象。一般通过实现 cloneable 接口实现该方法,在 Object 类中该方法是 native 方法,基于底层操作系统实现。

// 具体使用
A a1 = new A();
A a2 = (A)a1.clone();

当我们调用 clone() 方法后,首先根据原对象的大小申请内存空间,申请完内存空间后,将原对象内存域复制到新申请的内存空间,返回引用类型。也就是说,从内存地址来看,clone() 会创建一个全新的对象

但是实际上此方法实现的是浅拷贝

String特殊性: 因为他为引用型,而且他指向的值为常量,克隆出来的对象改变他的值。实际上是改变了克隆出来对象String类型成员的指向,不会影响被克隆对象的值及其指向。因为执行 cloned.name = "new";语句时,它作用相当于生成了一个新的string类型,然后又赋回给cloned.name。

如何用clone()方法实现深拷贝:

现在为了要在clone对象时进行深拷贝, 那么就要Clonable接口,覆盖并实现clone方法,除了调用父类中的clone方法得到新的对象, 还要将该类中的引用变量也clone出来。

使用该方式实现深克隆,需要注意以下几点:

  • 被克隆的类必须实现 Cloneable 接口。
  • 所有子对象也必须实现 Cloneable 接口,否则会抛出 CloneNotSupportedException 异常。
  • 所有子对象的 clone() 方法必须调用 super.clone() 并将其结果强制转换为子对象类型。
  • 所有子对象的 clone() 方法中,如果子对象包含其他子对象,需要递归调用其 clone() 方法以实现深克隆。
  • 如果被克隆的类和子对象包含不可变对象,则可以不用复制其副本,以提高性能。

如果要使Body对象在clone时进行深拷贝, 那么就要在Body的clone方法中,将源对象引用的Head对象也clone一份。

    static class Body implements Cloneable{
        public Head head;
        public Body() {}
        public Body(Head head) {this.head = head;}
 
        @Override
        protected Object clone() throws CloneNotSupportedException {
            Body newBody =  (Body) super.clone();
            newBody.head = (Head) head.clone(); //重写clone()方法,并对引用类型进行克隆
            return newBody;
        }
        
    }
    static class Head implements Cloneable{
        public  Face face;
        
        public Head() {}
        public Head(Face face){this.face = face;}
        @Override
        protected Object clone() throws CloneNotSupportedException {
            return super.clone();
        }
    } 

    public static void main(String[] args) throws CloneNotSupportedException {
        
        Body body = new Body(new Head());
        
        Body body1 = (Body) body.clone();
        
        System.out.println("body == body1 : " + (body == body1) );
        
        System.out.println("body.head == body1.head : " +  (body.head == body1.head));
        
        
    }

打印结果为:

body == body1 : false      //对象引用不一

body.head == body1.head : false  //对象属性的应用也不一样

由此可见, body和body1内的head引用指向了不同的Head对象, 也就是说在clone Body对象的同时, 也拷贝了它所引用的Head对象, 进行了深拷贝。

存在问题:对于Head的中的引用类型属性Face来说,Body是没有进行深拷贝的

那么如何实现真正的深拷贝:如果在拷贝一个对象时,要想让这个拷贝的对象和源对象完全彼此独立,那么在引用链上的每一级对象都要被显式的拷贝

BeanUtils工具类中的copyProperties方法是深拷贝还是浅拷贝:浅拷贝

Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表