- 浏览: 184516 次
- 性别:
- 来自: 上海
文章分类
最新评论
-
xoxoj:
如果发现input输入框里包含这些全角的内容,jquery应该 ...
全角正则 -
TJYCHYANGCHENHUI:
不对吧!你的第一句话说错了好吧,在没有开启事务的情况下,sa ...
hibernate入门(三)Session中的主要方法 -
leonardleonard:
好帖
js公共函数(utils.js) -
xyqqjy:
朋友你和我的现状很像啊!
我离职快一年了,一直没有再做开发这一 ...
浮躁,我 -
djy1135:
确实需要静一下心! 一样一样来吧。 东西学不半扔了,跟没学差 ...
浮躁,我
一:现在Clone已经不是一个新鲜词语了,伴随着“多莉”的产生这个词语确实很“火”过一阵子,在java中也有这么一个概念,它可以让我们很方便的“制造”出一个对象的副本来,下面来具体看看java中的Clone机制是如何工作的?
1.
Clone&Copy
假设现在有一个Employee对象,Employee tobby =new
Employee(“CMTobby”,5000),通
常我们会有这样的赋值Employee
cindyelf=tobby,这个时候只是简单了copy了一下reference,cindyelf和tobby都指向内存中同一个object,这样cindyelf或者tobby的一个操作都可能影响到对方。打个比方,如果我们通过cindyelf.raiseSalary()方法改变了salary域的值,那么tobby通过getSalary()方法得到的就是修改之后的salary域的值,显然这不是我们愿意看到的。我们希望得到tobby的一个精确拷贝,同时两者互不影响,这时候我们就可以使用Clone来满足我们的需求。Employee
cindy=tobby.clone(),这时会生成一个新的Employee对象,并且和tobby具有相同的属性值和方法。
2. Shallow
Clone&Deep
Clone
Clone是如何完成的呢?Object在对某个对象实施Clone时对其是一无所知的,它仅仅
是简单地执行域对域的copy,这就是Shallow
Clone。这样,问题就来了咯,以Employee为例,它里面有一个域hireDay不是基本型别的变量,而是一个reference变量,经过Clone之后就会产生一个新的Date型别的reference,它和原始对象中对应的域指向同一个Date对象,这样克隆类就和原始类共享了一部分信息,而这样显然是不利的.
这个时候我们就需要进行deep
Clone了,对那些非基本型别的域进行特殊的处理,例如本例中的hireDay。我们可以重新定义Clone方法,对hireDay做特殊处理,如下代码所示:
class
Employee implements Cloneable
{
public Object clone() throws
CloneNotSupportedException
{
Employee cloned = (Employee)
super.clone();
cloned.hireDay = (Date) hireDay.clone()
return
cloned;
}
}
3.
Clone()方法的保护机制
在Object中Clone()是被申明为protected的,这样做是有一定的道理的,以Employee
类为例,通过申明为protected,就可以保证只有Employee类里面才能“克隆”Employee对象,原理可以参考我前面关于public、protected、private的学习笔记。
4.
Clone()方法的使用
Clone()方法的使用比较简单,注意如下几点即可:
a. 什么时候使用shallow Clone,什么时候使用deep
Clone,这个主要看具体对象的域是什么性质的,基本型别还是reference variable
b.
调用Clone()方法的对象所属的类(Class)必须implements
Clonable接口,否则在调用Clone方法的时候会抛出CloneNotSupportedException。
二:有时我们确实需要clone一个对象,最好的方法还是使用Object的clone方法,由jdk调用native方法来实现,这样效率比较高。先来个shallow
clone,再来deep clone。
1:shallow clone
代码如下:
待clone的对象
package practisejava.others.clone;
/**
* 待clone的对象,必须实现Cloneable这个tag
interface
*/
public class ObjectToClone implements Cloneable{
private int i=0;
public void setNum(int i){
this.i=i;
}
public int getNum(){
return
this.i;
}
public void tellNum(){
System.out.println("the number is "+i);
}
// 重写Object的clone
public Object clone() throws CloneNotSupportedException {
return
(ObjectToClone)super.clone();
}
}
clone测试
package
practisejava.others.clone;
/**
* 测试clone是否成功
*/
public class
CloneTest {
public static void main(String[] args) {
ObjectToClone otc = new ObjectToClone();
otc.setNum(888);
// 开始clone了!
ObjectToClone cloneObject = null;
try {
cloneObject = (ObjectToClone) otc.clone();
}
catch (CloneNotSupportedException ex) {
System.out.println("Sorry,Clone Not Supported!");
}
// 测试clone是否成功
if(cloneObject!=null){
System.out.println("before clone");
System.out.println("ObjectToClone get number : " + otc.getNum()+"\n");
System.out.println("after clone");
System.out.println("ObjectToClone get number : " + otc.getNum());
cloneObject.setNum(999);
System.out.println("CloneObject get number : " +
cloneObject.getNum());
}
}
}
执行结果
before
clone
ObjectToClone get number : 888
after clone
ObjectToClone get
number : 888
CloneObject get number :
999
从运行结果看,修改了clone体的值并没有影响到原来被clone体的值,哈哈,clone成功。高兴得太早了,ObjectToClone里只有简单的非引用属性,如果有引用的属性,还能成吗?答案是否定的!看下面的例子:
被clone对象引用的对象
package practisejava.others.shallowclone;
public class ReferencedObject
{
private int i = 0;
public ReferencedObject(int i) {
this.i = i;
}
public void doubleValue(){
this.i =
2*this.i;
}
public int getNumber(){
return
this.i;
}
}
待clone对象
package
practisejava.others.shallowclone;
/**
*
必须实现Cloneable接口,否则调用函数的clone方法时会报CloneNotSupportedException错
*/
public
class ObjectForShallowClone implements Cloneable{
private int i =
0;
private ReferencedObject rf = null;
public void
setNum(int i) {
this.i = i;
}
public void
setReferencedObject(ReferencedObject rf){
this.rf = rf;
}
public int getNumber(){
return this.i;
}
public ReferencedObject getReferencedObject(){
return
this.rf;
}
// 重写Object的clone
public Object clone()
throws CloneNotSupportedException {
return
(ObjectForShallowClone)super.clone();
}
}
clone测试
package
practisejava.others.shallowclone;
/**
* clone测试
*/
public class
CloneTest {
public static void main(String[] args) {
ObjectForShallowClone ofsc = new ObjectForShallowClone();
ofsc.setNum(888);
ofsc.setReferencedObject(new
ReferencedObject(1));
// 开始clone了!
ObjectForShallowClone
deepCloneObject = null;
try {
deepCloneObject =
(ObjectForShallowClone) ofsc.clone();
} catch
(CloneNotSupportedException ex) {
System.out.println("Sorry,Clone
Not Supported!");
}
// 测试clone是否成功
if(deepCloneObject!=null){
System.out.println("before
clone");
System.out.println("ObjectForShallowClone get number : "
+ ofsc.getNumber());
System.out.println("ObjectForShallowClone
ReferencedObject get number :
"+ofsc.getReferencedObject().getNumber()+"\n");
deepCloneObject.setNum(999);
deepCloneObject.getReferencedObject().doubleValue();
System.out.println("after clone");
System.out.println("ObjectForShallowClone get number : " +
ofsc.getNumber());
System.out.println("ObjectForShallowClone
ReferencedObject get number : " +
ofsc.getReferencedObject().getNumber());
System.out.println("CloneObject get number : " +
deepCloneObject.getNumber());
System.out.println("CloneObject
ReferencedObject get number : " +
deepCloneObject.getReferencedObject().getNumber());
}
}
}
运行结果如下:
before clone
ObjectForShallowClone get number :
888
ObjectForShallowClone ReferencedObject get number : 1
after
clone
ObjectForShallowClone get number : 888
ObjectForShallowClone
ReferencedObject get number : 2
CloneObject get number : 999
CloneObject
ReferencedObject get number :
2
显然,修改了clone对象的引用对象的值后,被clone对象引用对象的值也随之改变。这不是我们想要的效果,改进的方法就是deep
clone。
2:deep clone
被clone对象引用的对象(比shallow clone多加了clone的方法)
package
practisejava.others.deepclone;
public class ReferencedObject implements
Cloneable{
private int i = 0;
public ReferencedObject(int i)
{
this.i = i;
}
public void doubleValue(){
this.i = 2*this.i;
}
public int getNumber(){
return
this.i;
}
// 重写clone的方法
public Object clone() throws
CloneNotSupportedException {
return
(ReferencedObject)super.clone();
}
}
待clone对象(在clone方法里同时clone引用对象)
package practisejava.others.deepclone;
import
practisejava.others.deepclone.ReferencedObject;
public class
ObjectForDeepClone implements Cloneable{
private int i = 0;
private ReferencedObject rf = null;
public void setNum(int i)
{
this.i = i;
}
public void
setReferencedObject(ReferencedObject rf){
this.rf = rf;
}
public int getNumber(){
return this.i;
}
public ReferencedObject getReferencedObject(){
return this.rf;
}
// 重写Object的clone
public Object clone() throws
CloneNotSupportedException {
ObjectForDeepClone cloneObject =
(ObjectForDeepClone)super.clone();
// 调用引用对象的clone方法
if(rf!=null){
ReferencedObject rfClone =
(ReferencedObject)rf.clone();
cloneObject.setReferencedObject(rfClone);
}
return
cloneObject;
}
}
clone测试
package
practisejava.others.deepclone;
public class CloneTest {
public static
void main(String[] args) {
ObjectForDeepClone ofdc = new
ObjectForDeepClone();
ofdc.setNum(888);
ofdc.setReferencedObject(new ReferencedObject(1));
//
开始clone了!
ObjectForDeepClone deepCloneObject = null;
try
{
deepCloneObject = (ObjectForDeepClone) ofdc.clone();
} catch (CloneNotSupportedException ex) {
System.out.println("Sorry,Clone Not Supported!");
}
//
测试clone是否成功
if(deepCloneObject!=null){
System.out.println("before clone");
System.out.println("ObjectForDeepClone get number : " +
ofdc.getNumber());
System.out.println("ObjectForDeepClone
ReferencedObject get number :
"+ofdc.getReferencedObject().getNumber()+"\n");
deepCloneObject.setNum(999);
deepCloneObject.getReferencedObject().doubleValue();
System.out.println("after clone");
System.out.println("ObjectForDeepClone get number : " +
ofdc.getNumber());
System.out.println("ObjectForDeepClone
ReferencedObject get number : " +
ofdc.getReferencedObject().getNumber());
System.out.println("CloneObject get number : " +
deepCloneObject.getNumber());
System.out.println("CloneObject
ReferencedObject get number : " +
deepCloneObject.getReferencedObject().getNumber());
}
}
}
运行结果:
before clone
ObjectForDeepClone get number :
888
ObjectForDeepClone ReferencedObject get number : 1
after
clone
ObjectForDeepClone get number : 888
ObjectForDeepClone
ReferencedObject get number : 1
CloneObject get number : 999
CloneObject
ReferencedObject get number : 2
发表评论
-
Android开源git40个App源码
2019-04-26 10:48 567(JamsMusicPlayer)很棒的音乐播放器( ... -
Quartz的cron表达式
2019-03-22 11:48 4001. Seconds 2. ... -
JAVA JS 身份证正则表达式
2012-03-28 16:36 1270String pattern = "( ... -
生产者消费者问题实现
2011-10-31 14:16 800这是个线程同步的经典例子,源代码如下: /** *经 ... -
设计模式----观察者模式Observer
2011-10-19 10:06 836Observer模式 Observer模式的功用,是希望两个 ... -
META-INF中的MANIFEST.MF的作用
2011-03-03 16:50 2018MANIFEST中的配置信息共 ... -
JAVA日期时间小结
2011-03-01 11:30 2168Java 语言的Calendar,GregorianCalen ... -
java读取Properties文件六种方法
2011-01-28 10:15 8841。使用java.util.Properties类的load( ... -
ireport相关之jasper
2010-11-09 13:57 1504ireport是工具,jasper才是核心。没有ireport ... -
用java实现发邮件
2010-08-06 22:49 989用java实现发邮件的原理非常简单,首先建立和邮件服务器的So ... -
Java 实现文件分割合并
2010-08-06 22:37 1183import java.io.*; class Fen{ ... -
java写的des加密解密
2010-08-06 22:02 1284首先说一下什么是DES加密 DES算法为密码体制中的对称密码 ... -
Jasper Report总结
2010-07-30 12:43 1734下载 Jasper: ... -
java给图片加水印,文字
2010-07-19 22:59 999import java.awt.AlphaComposite; ... -
JSP中的EL表达式
2010-07-11 23:19 734一、JSP EL语言定义 ... -
Java生成gif动画
2010-07-09 21:17 1389BufferedImage src = ImageI ... -
四个有用的Java过滤器收藏
2010-07-09 21:15 895一、使浏览器不缓存页面的过滤器 一、使浏览器不缓存页面的过滤 ... -
简捷强大的单文件XML操作工具类
2010-07-09 21:13 1014这个是XML操作工具类,只有一个类文件,使用的全部是JDK ... -
Java连接各种数据库
2010-07-09 21:08 7211、Oracle8/8i/9i数据库(thin模式) C ... -
java采集csdn论坛源码
2010-07-09 17:15 1317import java.io.BufferedReader; ...
相关推荐
在Java中实现深拷贝通常需要自定义`clone`方法或者使用序列化和反序列化技术。 对于`Cloneable`接口,当一个类需要支持`clone`操作时,应当实现这个接口。不过要注意的是,`Cloneable`接口本身没有任何方法,只是一...
Java中的`clone`方法是Java语言提供的一种复制对象的机制,它允许创建一个现有对象的副本,这个副本具有与原始对象相同的状态,但它们是独立的实体,对其中一个对象的修改不会影响另一个。`clone`方法是Java `Object...
Java中的对象创建主要有两种方式,即使用`new`操作符创建新对象以及通过`clone`方法...在实际编程中,还可以考虑使用其他技术,如拷贝构造函数或工厂方法,来替代或补充`clone`操作,以实现更安全、更可控的对象复制。
Java Web前台技术是Web应用程序开发中的重要组成部分,主要关注用户界面的设计、交互和用户体验。这份“Java Web前台技术”资料集全面涵盖了与之相关的多个关键知识点,旨在帮助开发者提升技能和效率。 一、HTML...
### Java 高级特性详解 #### 一、`hashCode` ...正确地重写 `equals` 和 `hashCode` 方法、使用 `Comparator` 进行排序、利用反射机制和序列化技术,以及实现 `clone` 方法都是开发高质量 Java 应用程序的重要技能。
以下是一些关键的Java知识点,源自《Java技术要点与面试经典2013版》的部分内容: 1. 一个".java"源文件可以包含多个类,但只能有一个公开类(public class),其他类可以是非公开的(如private或默认包访问)。...
在Java编程语言中,数组是一种基础且重要的数据结构,它用于存储同类型的多个元素。数组复制是编程中常见的...通过学习和熟练掌握这些技术,开发者能够更高效、更灵活地处理数组数据,进一步提升程序的稳定性和效率。
在Java开发领域,掌握核心知识点对于应对技术面试至关重要。根据提供的文件内容,我们可以提炼出一些关键的面试要点,并详尽地探讨它们。 首先,Java中所有类的父类是Object类。这是Java语言继承体系的基础,所有的...
在Java编程中,深拷贝和浅拷贝是两种复制对象的方法,它们涉及到对象的...在实现深拷贝时,可以通过重写`clone()`方法或使用序列化技术,但后者可能带来额外的时间开销。选择哪种方式取决于具体的应用场景和性能需求。
【Java面试+Java后端技术学习指南】 在Java领域,面试和实际开发是相辅相成的两个重要环节。为了成为一名出色的Java后端开发者,掌握扎实的理论基础、丰富的实战经验以及良好的问题解决能力至关重要。以下是一些...
《JAVA面试宝典》是一本全面涵盖Java技术体系和求职面试知识的指南,旨在帮助Java开发者准备面试,提升技能。本书共分为十章,从基础知识到框架应用,再到项目实战和面试题解析,覆盖了Java开发者的必备技能。 第一...
Java面试的准备可以分为几个部分,其中最重要的部分是Java技术相关,包括了Java的基础知识、核心API的解读以及Java中高级技术的理解。同时,面试者应该熟悉应聘流程,了解如何撰写简历,以及在面试中如何谈论福利...
这种操作常见于对象导向编程,例如在Java、Python、C#等语言中。通过克隆,我们可以创建一个原始对象的独立副本,对副本进行修改不会影响原始对象,这在数据处理和并发编程中尤其有用。 2. **深度克隆与浅克隆** -...
Java是一种广泛使用的面向对象的编程语言,其高级技术在面试中常常被重点考察。以下是针对提供的文件内容的一些关键知识点的详细解释: 1. **接口与内部类**:接口是Java中用于实现多继承的一种机制,它包含抽象...
GRPC-Java 源码环境构建是一个相对复杂的过程,需要具备一定的技术基础和经验。本文将详细介绍 GRPC-Java 源码环境构建的步骤和过程,旨在帮助读者快速搭建 GRPC-Java 源码环境。 一、Clone GRPC-Java 源码 GRPC-...
此外,书中还涉及了对象克隆(clone)的概念,这是Java中实现对象深度复制的技术。 Java SE语法是程序员必须掌握的基础,包括Java语言中的关键字和特殊符号的使用,例如“&”和“&&”的区别、goto语句的不存在、...
Java面试题常常围绕其核心概念和技术,包括内存管理、数据结构和多线程等方面。下面我们将深入探讨这些知识点。 **Java内存分配** Java内存分为几个主要区域: 1. **静态区(方法区)**:也被称为 PermGen 或 ...