分析java中clone()方法 (转载+修改)


  Java中的clone() 方法

java所有的类都是从java.lang.Object类继承而来的,而Object类提供下面的方法对对象进行复制。

 protected native Object clone() throws CloneNotSupportedException;

这个javabean必须实现一个标识接口,Cloneable,表明这个javabean支持复制,如果没有实现这个接口,而调用clone()方法,编译器就会抛出CloneNotSupportedException异常。java语言提供的Cloneable接口只起一个作用,就是在运行时通知虚拟机可以安全的在这个类上使用clone方法,通过调用这个clone()方法可以得到一个对象的复制(Object 类本身不实现Cloneable接口);

克隆满足的条件:

clone()方法将对象复制了一份并返还给调用者。所谓“复制”的含义与clone()方法是怎么实现的有关。一般而言,clone方法满足以下条件:

1).对任何的对象x,都有:x.clone()!=x.即克隆对象与原对象不是同一个对象。

2).对任何的对象x,都有:x.clone().getClass==x.getClass(),即克隆对象与原对象的类型一样。

3).如果对象x的equals()方法定义恰当的话,x.clone().equals(x)应当是成立的。

克隆分为两种方式:深克隆和浅克隆

浅克隆(浅复制):被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。

深克隆(深复制):被复制对象的所有变量(非引用其他对象的变量)都含有与原来的对象相同的值,那些引用其他的对象的变量将指向被复制过的新对象,而不是原有的那些被引用的对象。即:深复制把要复制的对象所引用的对象都复制了一遍,而这种堆被引用的对象的复制叫做间接复制。

以下是浅复制的例子:

====================================================================================

客户端:

public class TheGreatestSage
 {

  private Monkey monkey=new Monkey();
  public void change()
   {
   	  Monkey copy;
   	  copy=(Monkey)monkey.clone();
  	  System.out.println("原来生日:"+monkey.getBirthday());
  	  System.out.println("复制的生日:"+copy.getBirthday());
   	  System.out.println("猴子是不是一个对象"+(monkey==copy));
    	  System.out.println("金箍棒是否是一个"+(monkey.getStaff()==copy.getStaff()));
   }
  public static void main(String args[])
   {
    	 new TheGreatestSage().change();
   }
 }

猴子类(可以复制的类)

import java.util.Date;

public class Monkey implements Cloneable
 {
  private int height;
  private int weight;
  private GoldRingedStaff staff;
  private Date birthday;
  public Monkey()
   {
    	this.birthday=new Date();
   }
  public Date getBirthday()
   {
    	return birthday;
   }
  public void setBirthday(Date birthday)
   {
   	 this.birthday = birthday;
   }
  public int getHeight()
   {
   	 return height;
   }
  public void setHeight(int height)
   {
    	this.height = height;
   }
  public GoldRingedStaff getStaff()
   {
   	 return staff;
   }
  public void setStaff(GoldRingedStaff staff)
   {
    	this.staff = staff;
   }
  public int getWeight()
   {
   	 return weight;
   }
  public void setWeight(int weight)
   {
    	this.weight = weight;
   }
  public Object clone()
   {
   	 Monkey temp=null;
   	 try
     {
     	 temp=(Monkey)super.clone();
      }
    catch (CloneNotSupportedException e)
     {
    	  // TODO 自动生成 catch 块
     	 e.printStackTrace();
     }
    finally
    {
    	 return temp;
    }
   }
 }

金箍棒(复制类引用的类)

public class GoldRingedStaff
 {
  private  float height=100.0f;
  private float diameter=10.0f;
  public void grow()
   {
    	this.height*=2.0;
    	this.diameter*=2;
   }
  public void shrink()
   {
    	this.height/=2;
   	 this.diameter/=2;
   }
  public float getDiameter()
   {
   	 return diameter;
   }
  public void setDiameter(float diameter)
   {
   	 this.diameter = diameter;
   }
  public float getHeight()
   {
   	 return height;
   }
  public void setHeight(float height)
   {
   	 this.height = height;
   }

 }

====================================================================================

运行结果:

原来生日:Mon May 07 09:27:12 CST 2007
复制的生日:Mon May 07 09:27:12 CST 2007
猴子是不是一个对象false
金箍棒是否是一个true

由结果可以看出:

复制的对象和原来的对象有相同的生日,而对象本身不相等。说明他们是克隆关系。 但复制的对象和原对象的金箍棒是一样的,说明二者持有的是同一个对象。

####################################################################################

深克隆例子:

为了做到深复制,所有需要复制的对象都要实现java.io.Serializable接口。

=========================================================================================

客户端

import java.io.IOException;

public class TheGreatestSage
 {
  private Monkey monkey=new Monkey();
  public void change() throws IOException, ClassNotFoundException
   {
   	 Monkey copy;
    	copy=(Monkey)monkey.deepClone();
    	System.out.println("原来生日:"+monkey.getBir());
    	System.out.println("复制的生日:"+copy.getBir());
    	System.out.println("猴子是不是一个对象"+(monkey==copy));
   	 System.out.println("金箍棒是否是一个"+(monkey.getStaff()==copy.getStaff()));
   }
  public static void main(String args[]) throws IOException, ClassNotFoundException
   {
  	  new TheGreatestSage().change();
   }
 }

猴子类(可以复制的类)

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.Date;

public class Monkey implements Cloneable,Serializable
 {
  private int height;
  private int weight;
  private GoldRingedStaff staff;
  private Date bir;
  public Monkey()
   {
    	this.bir=new Date();
    	this.staff=new GoldRingedStaff();
   }
  public Date getBir()
   {
   	 return bir;
   }
  public void setBir(Date bir)
   {
 	  this.bir = bir;
   }
  public int getHeight()
   {
  	  return height;
   }
  public void setHeight(int height)
   {
   	 this.height = height;
   }
  public GoldRingedStaff getStaff()
   {
   	 return staff;
   }
  public void setStaff(GoldRingedStaff staff)
   {
    	this.staff = staff;
   }
  public int getWeight()
   {
   	 return weight;
   }
  public void setWeight(int weight)
   {
   	 this.weight = weight;
   }
  /*
   * 深克隆方法
   */
  public Object deepClone() throws IOException, ClassNotFoundException
   {
    //首先将对象写到流里
   	 ByteArrayOutputStream bo=new ByteArrayOutputStream();
   	 ObjectOutputStream oo=new  ObjectOutputStream(bo);
    	oo.writeObject(this);
    //然后将对象从流里读出来
   	 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
   	 ObjectInputStream oi=new ObjectInputStream(bi);
   	 return (oi.readObject());
   }
  /*
   * 浅克隆方法
   */
  public Object clone()
   {
   	 Monkey temp=null;
    try
     {
     	 temp=(Monkey)(super.clone());
     }
    catch (CloneNotSupportedException e)
     {
     	 // TODO 自动生成 catch 块
    	  e.printStackTrace();
     }
   	 return temp;
   }
 }

金箍棒(复制类引用的类)

import java.io.Serializable;

public class GoldRingedStaff implements Cloneable,Serializable
 {
  private float height=100f;
  private float diameter=10.0f;
  public void grow()
   {
    	this.height*=2;
   	this.diameter*=2;
   }
  public void shrink()
   {
   	 this.height/=2;
  	  this.diameter/=2;
   }
  public float getDiameter()
   {
   	 return diameter;
   }
  public void setDiameter(float diameter)
   {
    	this.diameter = diameter;
   }
  public float getHeight()
   {
    	return height;
   }
  public void setHeight(float height)
   {
   	 this.height = height;
   }
 }

=========================================================================================

运行结果

原来生日:Mon May 07 10:38:21 CST 2007
复制的生日:Mon May 07 10:38:21 CST 2007
猴子是不是一个对象false
金箍棒是否是一个false

由结果可以看出:使用了深复制,除了将目标类复制,也把所有引用的的对象都复制了一遍。

===================================

===================================

===================================

===================================

浅析java中clone()方法 

        java中我们可能都遇到过这样的情况,在我们将一个对象做为参数传给一个函数的时候,我们希望在这个函数中所做的操做,并不会影响到这个对象本身。但是在java传递都是引用,所以往往我们在函数内部改变了对象的某一个值,在函数外面调用该对象的时候,相应的值也同样被改变了,例如下面的程序:

class Test

{

static void myMethod(Point pt1)

{

pt1.x = 23;

System.out.println("x="+pt1.x);

}

   public static void main(String[] args)

{

Point pt = new Point(2,4);

System.out.println("x="+pt.x);

myMethod(pt);

System.out.println("x="+pt.x);

}

}

class Point{

   int x,y;   

   Point (int x,int y)

   {

       this.x = x;

      this.y = y;

   }

}

输出的结果是

x=2

x=23

x=23

但是我们想要的结果是在我们调用了函数myMethod()方法后x的值不会改变,仍然是2。由于java中的传参是引用类型,所以会出现这样的结果,我们希望传递的是对象的一份拷贝,所以这里就用到了Object的clone()方法。

       克隆的实现需要一下几步:

在派生类中覆盖基类的clone()方法,并声明为public。

在派生类的clone()方法中,调用super.clone()。

在派生类中实现Cloneable接口。Cloneable接口没有任何抽象的方法,这样的成为标识接口。实现这个接口,只是为了告诉编译器这个对象可以被克隆了。我们按照上面的步骤将上面的代码修改如下:

class Test
{
static void   myMethod(Point pt1)
{
pt1.x = 23;
System.out.println("x="+pt1.x);
}
   public static void main(String[] args)
   {
  Point pt = new Point(2,4);
  System.out.println("x="+pt.x);
  Point pt2 = (Point)pt.clone();
  myMethod(pt2);
  System.out.println("x="+pt.x);
   }
}
class Point implements Cloneable{
   int x,y;   
   Point (int x,int y)
   {
       this.x = x;
      this.y = y;
   }
   public Object clone()
   {
  Point p = null;
  try
  {
  p = (Point)super.clone();
  }
  catch (Exception e)
  {
  e.printStackTrace();
  }
  return p;
   }
}

输出的结果是:

x=2
x=23
x=2

首先我们在派生类中覆盖了Object类的Clone()方法,并声明为public的。然后我们调用了super.clone()方法,这里会抛出一个异常(对于这个异常大家可以自己查看java的帮助文档),所以必须用try……catch……语句捕获,然后返回此对象。这里需要说明一下,Clone()方法返回的是Object类型的,所以需要强制类型转换

       对于javaclone()方法的浅析希望能给您带来帮助。

==

时间: 2024-10-25 15:27:38

分析java中clone()方法 (转载+修改)的相关文章

JAVA中toString方法的作用

以下是对在JAVA中toString方法的作用进行了详细的分析介绍,需要的朋友可以参考下   因为它是Object里面已经有了的方法,而所有类都是继承Object,所以"所有对象都有这个方法". 它通常只是为了方便输出,比如System.out.println(xx),括号里面的"xx"如果不是String类型的话,就自动调用xx的toString()方法 总而言之,它只是sun公司开发java的时候为了方便所有类的字符串操作而特意加入的一个方法  回答补充:写这个

jQuery中clone()方法用法实例_jquery

本文实例讲述了jQuery中clone()方法用法.分享给大家供大家参考.具体分析如下: 此方法克隆匹配的DOM元素并且选中这些克隆的副本以及其所有的事件处理. 语法结构: 复制代码 代码如下: $(selector).clone(Events,deepEvents) 参数列表: 参数 描述 Events 可选.布尔值,用来规定事件处理函数是否被复制.默认为false. true-复制元素的所有事件处理. false-不复制元素的事件处理. deepEvents 可选.布尔值,用来规定是否对事件

JAVA中static方法的用法实例详解_java

本文实例讲述了JAVA中static方法的用法.分享给大家供大家参考,具体如下: static表示"全局"或者"静态"的意思,用来修饰成员变量和成员方法,也可以形成静态static代码块,但是Java语言中没有全局变量的概念. 被static修饰的成员变量和成员方法独立于该类的任何对象.也就是说,它不依赖类特定的实例,被类的所有实例共享.只要这个类被加载,Java虚拟机就能根据类名在运行时数据区或者方法区内找到他们.因此,static对象可以在它的任何对象创建之前访

JQuery中clone方法复制节点

  本文实例讲述了JQuery中clone方法复制节点.分享给大家供大家参考.具体如下: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DT

JQuery中clone方法复制节点_jquery

本文实例讲述了JQuery中clone方法复制节点.分享给大家供大家参考.具体如下: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <

java中除了方法可以使用throws关键词抛出异常外,类可以吗

问题描述 java中除了方法可以使用throws关键词抛出异常外,类可以吗 java中除了方法可以使用throws关键词抛出异常外,类可以吗,可不可以抛来抛去而不处理它 解决方案 方法中如果需要抛出异常,就只能用throws异常的,那么调用这个方法的地方必须处理这个抛出的异常.如果调用了抛出异常的方法,要么使用try-catch处理该异常,要么直接抛给它的上层调用者.最后如果都没有处理,那么运行时就由JVM进行处理,那么程序就会出错了. 解决方案二: 类不可以抛出异常,方法抛出的异常交给调用者处

在java中一个方法抛两个异常会怎样

问题描述 在java中一个方法抛两个异常会怎样 在一个java方法中同时用throw和throws抛出异常.会有不良的影响么.会不会有一个一个异常抛不出去的情况发生啊?求大神帮帮忙 解决方案 他俩用的地方不一样,throws是写在方法后面,其他地方调用时,要捕获,throw是在方法内直接抛出,可以一起用throw触发了,估计就到不了throws的捕获了,看你具体怎样用的 解决方案二: 方法声明时可以抛出异常,但是并不代表调用这个方法时会发生异常. 测试要构造异常条件才能走入异常分支的啊.例如:

java中同一个方法可以被几个类或者被几个对象共享

问题描述 java中同一个方法可以被几个类或者被几个对象共享 java中同一个方法可以被几个类或者被几个对象共享java中同一个方法可以被几个类或者被几个对象共享 解决方案 方法本质上是字节码序列,底层是指令集合.方法是通过对象调用的,对象是存储在堆中的,是所有线程共享的.方法是类型信息,不存在共享这个说法. 解决方案二: java 中的方法都是在类中的,而对于你说的方法可以被几个类或者几个对象共享,这个问题问的没有多大意义,方法属于类的方法,不会被共享,可以被子类复写和调用. 解决方案三: j

跪求!!!java中,方法能调用自身吗?

问题描述 跪求!!!java中,方法能调用自身吗? 为实现对Student类中age的封装,使用了setage(),想实现当年龄不在一定范围内是提示输入错误并重新输入,重新输入我想通过再次运行setage()来实现,用this会出错,可是应该怎样操作?代码如下:public void setAge(int age) { if(this.age<15) { System.out.println("输入有误,请重新输入"); //this.setAge(int age); } els