浅析Java浅克隆机制

来源:互联网 发布:dts音效软件怎么下载 编辑:程序博客网 时间:2024/05/27 19:25
克隆定义:
       克隆是指生物体通过体细胞进行的无性繁殖,以及由无性繁殖形成的基因型完全相同的后代个体组成的种群。通常是利用生物技术由无性生殖产生与原个体有完全相同基因组织后代的过程。 
           
个人理解:
        就是完全复制一个一模一样的物件出来,复制完成后,这两个物件分别成为了一个独立的个体,它们单独所做的改变并不影响另一个物件。
      Java中的克隆就是这个道理。克隆对象时,会复制当前对象的副本,副本复制成功后。当前对象的改变并不会影响副本的改变,反之也是。但是,Java中的克隆又分为浅克隆和深度克隆:

 浅深克隆之别:
       当前对象的成员变量只有值类型时,也就是简单的数据类型,并不牵涉到复合数据类型,即引用数据类型 ,我们称之为浅克隆。当当前对象的成员变量包含复合数据类型时,那我们就得深度克隆了,如果只进行浅克隆,那副本得到的复合类型的成员变量只会是当前对象复合类型成员变量的引用。副本和当前的对象的复合类型的成员变量会指向同一块内存地址区域。当副本改变复合类型的成员变量时,当前对象的复合类型的成员变量的值也会改变。这就不符合我们克隆的要求了。要进行深度克隆,才能解决这个问题。在这里,我只先说下浅克隆,深度克隆后边再说吧。

其实,要进行浅克隆很简单,只要明白Java的Object类和Java虚拟机(JVM)的运行机制就可以搞定了,只有明白原理才能举一反三。 
Java的Object类:
        我们进行克隆时,要用到Object类中的clone()方法,Object类中有很多方法,在这里我们这只说该方法,其他方法有兴趣可以自行查看。
       我们知道,在Java中,我们所有的类(不包含Object类) 都是Object类的子类或间接子类,所以,我们所有的类中都包含了这个clone()这个方法, 但是为什么我们不能直接调用clone()这个方法进行克隆呢。因为clone()方法的访问权限修饰符是protected,也就是受保护的。protected权限修饰符规定了:其它包的类和非子类不能访问  。如果我们想直接调用clone()这个方法时,我们必须保证当前类和Object类在同一包中,这就要求我们的包名必须为java.lang中,这显然不可能的,定义包名时,是不允许我们这样做的。所以,我们只能在子类中覆盖(重写)clone()方法,并将访问权限提升为public,这样复制对象时,就可以直接调用clone()方法。但是,我们怎样重写Object类的clone()方法呢?我们只需要在本类中使用super关键字即可。super.clone()即是调用Object类中的clone()方法。

JVM(Java虚拟机):
       当对象调用Object类中的clone()方法时,  JVM将会逐个复制该对象的成员变量,然后创建一个新的对象,所以JVM要求调用clone()方法的对象必须实现Cloneable借口。Cloneable接口中没有任何方法,该接口唯一的作用是让JVM知道实现该接口的对象是可以被克隆的。

要被克隆对象的类:

package com.jingxuan1;
public class Person implements Cloneable {
 String name;
 int age;
 public Person(String name, int age) {
  super();
  this.name = name;
  this.age = age;
 }
 @Override
 public Object clone() throws CloneNotSupportedException {
  // TODO Auto-generated method stub
  /*
   * Object object = super.clone(); 
   *       object其实指向当前类的对象的地址区域,并不是指向Object类的对象的地址区域,
   *            那你也可以用:Person
   *       object=(Person)super.clone(); 
   * return object; 也可以使用下面的方式直接返回当前调用clone()方法的对象的副本
   */
  return super.clone();
 }
 void print() {
  System.out.println("Name:" + name + "\nAge:" + age);
 }
}

测试类:


package com.jingxuan1;
public class TestPerson {
 /**
  * @param args
  * @throws CloneNotSupportedException
  */
 public static void main(String[] args) throws CloneNotSupportedException {
  // TODO Auto-generated method stub
 
  Person p1 = new Person("jingxuan1", 20);
  System.out.println("输出对象p1:");
  p1.print();
  System.out.println();
 
  Person p2 = (Person) p1.clone(); // 克隆对象p1
  // 改变下p2,看看是否为影响p1对象
  p2.name = "jingxuan2";
  p2.age = 25;

  System.out.println("输出对象p2:");
  p2.print(); // 输出p2对象的信息
  System.out.println();
 
  System.out.println("输出对象p1:");
  p1.print(); // 输出p1对象的信息

 }
}

测试结果:

输出对象p1:
Name:jingxuan1
Age:20

输出对象p2:
Name:jingxuan2
Age:25
 
输出对象p1:
Name:jingxuan1
Age:20

        看到没,对象p2的改变并不影响对象p1,JVM在克隆对象p1时,同样为对象p2分配了内存空间,所以无论对象p1或对象p2怎样改变都不会影响到另外对象的状态,它们的成员变量的内存地址是不一样的
原创粉丝点击