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

时间:2022-12-13 11:14:41

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中我们可能都遇到过这样的情况,在我们将一个对象做为参数传给一个函数的时候,我们希望在这个函数中所做的操做,并不会影响到这个对象本身。但是在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()方法的浅析希望能给您带来帮助。

==

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

  1. Java中clone方法的使用

    什么是clone 在实际编程过程中,我们常常要遇到这种情况:有一个对象object1,在某一时刻object1中已经包含了一些有效值,此时可能会需要一个和object1完全相同新对象object2,并 ...

  2. Java基础——clone()方法浅析

    一.clone的概念 clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那 ...

  3. 详细分析 Java 中实现多线程的方法有几种?(从本质上出发)

    详细分析 Java 中实现多线程的方法有几种?(从本质上出发) 正确的说法(从本质上出发) 实现多线程的官方正确方法: 2 种. Oracle 官网的文档说明 方法小结 方法一: 实现 Runnabl ...

  4. java中sort方法的自定义比较器写法(转载)

    java中sort方法的自定义比较器写法 摘要 在做一些算法题时常常会需要对数组.自定义对象.集合进行排序. 在java中对数组排序提供了Arrays.sort()方法,对集合排序提供Collecti ...

  5. Java的clone方法效率问题

    在Java中,经常会需要新建一个对象,很多情况下,需要这个新建的对象和现有的某个对象保持属性一致. 那么,就有两种方式来实现这个对象的构造: ①通过新建一个对象,为这个对象的属性根据原有对象的属性来进 ...

  6. java中clone的深入理解

    Java中Clone的概念大家应该都很熟悉了,它可以让我们很方便的“制造”出一个对象的副本来,下面来具体看看java中的Clone机制是如何工作的?      1. Clone和Copy      假 ...

  7. Map java中的map 如何修改Map中的对应元素

    Map java中的map 如何修改Map中的对应元素 Map以按键/数值对的形式存储数据,和数组非常相似,在数组中存在的索引,它们本身也是对象.         Map的接口         Map ...

  8. 从虚拟机指令执行的角度分析JAVA中多态的实现原理

    从虚拟机指令执行的角度分析JAVA中多态的实现原理 前几天突然被一个"家伙"问了几个问题,其中一个是:JAVA中的多态的实现原理是什么? 我一想,这肯定不是从语法的角度来阐释多态吧 ...

  9. Java中clone的写法

    Cloneable这个接口设计得十分奇葩,不符合正常人的使用习惯,然而用这个接口的人很多也很有必要,所以还是有必要了解一下这套扭曲的机制.以下内容来自于对Effective Java ed 2. it ...

随机推荐

  1. SVN使用教程之-分支/标记 合并 subeclipse (转)

    首先说下为什么我们需要用到分支-合 并.比如项目demo下有两个小组,svn下有一个trunk版.由于客户需求突然变化,导致项目需要做较大改动,此时项目组决定由小组1继续完成原来正 进行到一半的工作[ ...

  2. Java总结篇系列:Java 反射

    Java反射: package com.corn; import java.lang.reflect.Constructor; import java.lang.reflect.Field; impo ...

  3. BZOJ3012 : [Usaco2012 Dec]First!

    建立Trie,那么成为答案的串必须满足其终止节点到根路径上没有其它点. 对于Trie上每个节点维护一个bitset,表示哪些字符必须在哪些字符之前. 每到达一个可能成为答案的终止节点,对图进行拓扑排序 ...

  4. POJ 3670 Eating Together (DP,LIS)

    题意:给定 n 个数,让你修改最少的数,使得它变成一个不下降或者不上升序列. 析:这个就是一个LIS,但是当时并没有看出来...只要求出最长LIS的长度,用总数减去就是答案. 代码如下: #inclu ...

  5. phpcms v9更改后台文章排序的方法

    后台文章排序怎么才可以按自己输入的数字排列?如按4,3,2,1,从大到小排列?实现方法如下: 修改文件: phpcms\modules\content 中的 content.php 代码如下: $da ...

  6. windows上定时执行php文件

    <?php $fp = fopen("E:/wwwroot/test/plan.txt", "w+"); fwrite($fp, date("Y ...

  7. Django models中的null和blank的区别

    blank在数据库上存储的是一个空字符串 如需设置字段可以为空:blank=True,默认为blank=False(字段必须填写); null在数据库上表现为NULL,而不是一个空字符串 如需设置字段 ...

  8. VNC 分辨率修改

    正确的: vncserver -geometry 1280x1024 错误的: vncserver -geometry 1280*1024

  9. 探索微信小程序之路

    记录一下每日的知识点,时不时温习一下. 视图与渲染对于页面中的数据,以json的方式存放在js文件的data中 判断的使用: <view wx:if='{{true}}'> 为真时显示 & ...

  10. Visual Studio Code 显示隐藏的&period;git文件和目录

    在默认设置中,Visual Studio Code 将下列文件文件排除在显示列表中: "files.exclude": { "**/.git": true, & ...