【Java基础】对象的拷贝与创建

134 阅读3分钟

对象创建

  • 使用 new 关键字
  • 反射机制
  • 实现 Cloneable 接口,使用 clone 方法创建对象
  • 序列化和反序列化 特点:
  • 方式 1 和方式 2 中,都明确地显式地调用了对象的构造函数。
  • 方式 3 中,是对已经的对象,在内存上拷贝了一个影印,并不会调用对象的构造函数。
  • 方式 4 中,对对象进行序列化,转化为了一个文件流,再通过反序列化生成一个对象,也不会调用构造函数。

new和clone创建对象的对比

  • JVM 对使用 new 方法创建对象的方式进行了优化,默认情况下,new 的效率更高。
  • new 方式创建对象时,会调用类的构造函数。若构造函数中有耗时操作,则会影响 new 方法创建对象的效率。
  • clone 方式创建对象,并不会调用类的构造函数。

对象拷贝

拷贝,顾名思义就是为了获得一个相同的对象,而不需要我们再人为的创建和赋值。

浅拷贝

对基本数据类型进行值传递,对引用数据类型进行引用传递般的拷贝。

数据类型是基本数据类型的成员变量:浅拷贝会直接进行值传递,也就是将这个属性值复制一份给新的对象,因为是两份不同的数据,所以对其中一个对象的该成员变量值进行修改,不会影响另一个对象拷贝得到的数据。

数据类型是引用数据类型的成员变量:如成员变量是某个数组或某个类的对象等,那么浅拷贝会进行引用传递,也就是只是将该成员变量的引用值(即内存地址)复制一份给新的对象,也就说这两个不同对象的该成员变量都指向了同一个地址,此时在一个对象中修改该成员变量就会影响到另一个对象所拷贝得到的数据。

实现浅拷贝的方法也很简单,只需要将需要拷贝的类实现 Cloneable 接口并覆写 clone() 方法即可

public class Person implements Cloneable {
    ...
    @Override public Object clone() { 
    //浅拷贝 
    try { 
        // 直接调用父类的clone()方法 
        return super.clone(); 
        } catch (CloneNotSupportedException e) { 
            return null; 
        } 
    }
    ...
}

深拷贝

对基本数据类型进行值传递,对引用数据类型,创建一个新的对象,并复制其内容。 深拷贝的特点:

  • 对于基本数据类型的成员对象,直接将属性值赋值给新的对象。基础类型的拷贝,其中一个对象修改该值,不会影响另外一个(和浅拷贝一样)。
  • 对于引用类型,比如数组或者类对象,深拷贝会新建一个对象空间,然后拷贝里面的内容,所以它们指向了不同的内存空间。改变其中一个,不会对另外一个也产生影响(和浅拷贝不同)。
  • 对于有多层对象的,每个对象都需要实现 Cloneable 并重写 clone() 方法,进而实现了对象的串行层层拷贝。
  • 深拷贝相比于浅拷贝速度较慢并且花销较大。
public class Subject implements Cloneable { 
    ...
    @Override 
    protected Object clone() throws CloneNotSupportedException { 
        return super.clone(); 
    }
    ...
}

public class Person implements Cloneable {
    /** 
      * 引用数据类型 
      */ 
    private Subject subject;
    ...
    @Override public Object clone() { 
    //浅拷贝 
    try { 
        // 直接调用父类的clone()方法 
        return super.clone(); 
        } catch (CloneNotSupportedException e) { 
            return null; 
        } 
    }
    ...
}

参考文档

深拷贝、浅拷贝和clone、new方法效率对比

大聪明教你学Java | 面试官:谈谈你对深拷贝和浅拷贝的理解