对象的拷贝[深拷贝和浅拷贝]:
i.关于clone[对象拷贝]——在实际编程过程,有时候我们会遇到一种情况:当你有一个对象A,在某一个时刻,A已经保存了对应的属性值,而且这些值本身是有效的,这个时候可能需要一个和A完全相同的对象B,并且当B里面的属性值发生变化的时候,A中的属性值不受影响,可以理解为A和B独立,但是B的初始化不是按照我们平时创建该对象的时候的初始化操作,B的初始化数据完全来自A。对Java存储模型了解的人都明白,在Java里面如果针对两个对象引用采取赋值操作的时候,仅仅是让两个引用指向了同一对象,如果其中一个引用里面的对象属性改变的时候会影响另外一个对象属性跟着改变,所以Java语言本身的对象赋值语句是不能完成上边的需求的。在这种时候,就需要用到Object类里面的通用方法clone(),这里需要说明的是:
通过clone()方法创建的对象是一个新对象,它可以认为是源对象的一个拷贝,但是在内存堆中,JVM会为这个拷贝分配新的对象存储空间来存放该对象的所有状态
该拷贝和普通对象使用new操作符创建的对象唯一的区别在于初始值,这个拷贝的初始值不是对象里面成员的默认值,而是和源对象此刻状态的成员的值是一样的
下边这段代码是clone方法的运用:
publicclassTesting{
publicstaticvoidmain(Stringargs[]){
AClassclass1=newAClass();
class1.a=12;
AClassclass2=(AClass)class1.clone();
System.out.println(class2.a);
System.out.println(class1==class2);
}
}
classAClassimplementsCloneable{
publicinta=0;
publicObjectclone(){
AClasso=null;
try{
o=(AClass)super.clone();
}catch(CloneNotSupportedExceptionex){
ex.printStackTrace();
}
returno;
}
}
上边这段代码运行结果输出为:
12
false
可以知道的就是成功复制了一个AClass的对象,该对象的引用为class1,而拷贝对象的引用为class2,这两个引用通过==比较输出为false,证明这两个引用不是指向了同一个对象,而且拷贝对象里面的a的值和class1引用的对象里面的a的值是一样的,都是12,这样就成功完成了对象的拷贝过程。若你对上边这段代码还有不了解的地方可以尝试将下边的代码修改掉:
AClassclass2=(AClass)class1.clone()修改为:AClassclass2=class1;
改了过后,输出结果应该为:
12
true
所以在对象的clone过程,需要注意的几点有:
[1]希望能够提供对象clone功能的类必须实现Cloneable接口,这个接口位于java.lang包里面
[2]希望提供对象clone功能的类必须重载clone()方法,在重载过程可以看到这句话:super.clone();也就是说,不论clone类的继承结构如何,我们在对象拷贝的时候都直接或简介调用了Object的clone()方法。而且细心留意可以看到Object的clone方法是protected域的,也就是说这个方法只有Object的子类可以调用,而在重载的时候将clone方法修饰符改为public
[3]还有一点很重要就是Object源代码里面的clone()方法是native方法,一般而言,对JVM来说,native方法的效率远比java中的普通方法高,这就是为什么我们在复制一个对象的时候使用Object的clone()方法,而不是使用new的方式。
[4]Cloneable接口和我们在编写IO程序的时候序列化接口一样,只是一个标志,这个接口是不包含任何方法的,这个标志主要是为了检测Object类中的clone方法,若我们定义的类想要实现拷贝功能,但是没有实现该接口而调用Object的clone方法,那么就会出现语句中catch块里面的异常错误,抛出CloneNotSupportedException。
ii浅拷贝——在对象clone的过程中,浅拷贝又称为“影子clone”,先看一段代码:
//这里先定义一个类
classAClass{
publicinta;
publicAClass(inta){this.a=a;}
publicvoidchange(){a+=12;}
publicStringtoString(){return"AValueis"+this.a;}
}
//定义一个clone类,里面包含了AClass的对象引用
classBClassimplementsCloneable{
publicinta=12;
publicAClassobj=newAClass(11);
publicObjectclone(){
BClassobject=null;
try{
object=(BClass)super.clone();
}catch(CloneNotSupportedExceptionex){
ex.printStackTrace();
}
returnobject;
}
}
publicclassTestClone{
publicstaticvoidmain(Stringargs[]){
BClassclass1=newBClass();
class1.a=15;
System.out.println(class1.a);
System.out.println(class1.obj);
BClassclass2=(BClass)class1.clone();
class2.a=22;
class2.obj.change();
System.out.println(class1.a);
System.out.println(class1.obj);
System.out.println(class2.a);
System.out.println(class2.obj);
}
}
运行上边这段代码会有以下输出:
15
AValueis11
15//这里拷贝成功了
AValueis23//!!!不对,根本没有调用class1里面的obj的change方法,所以不应该修改class1里面的obj里面的变量a的值【初衷】
22
AValueis23
不知细心的读者有没有发现输出和我们预期的拷贝不一样,虽然class2引用的对象是从class1拷贝过来的,class2里面的引用obj和class1里面的引用obj实际上还是指向了同一个对象,其含义在于,拷贝的初衷是要复制一个一模一样的对象,包括对象里面的对象也应该实现的是复制操作,它最终的目的是保证class1和class2本身的属性以及class1和class2里面的对象引用的属性在拷贝过后的各种相关操作里面相互独立,上边输出证明了class1和class2里面的变量a确实已经拷贝成功,但是class1和class2里面的AClass对象的引用obj在拷贝过后还是指向了同一个对象,所以拷贝结束过后,调用class2的obj的change方法的时候,也修改了class1里面的obj指向的对象里面的值。所以在Java里面我们把上边的拷贝过程称为“浅拷贝”,同样又称为“影子clone”。
从这里可以知道,在JVM的对象复制里面,实际上基本数据类型可以直接通过这种方式来进行拷贝工作,而非原始类型这样操作了过后拷贝的对象仅仅拷贝了对象里面的基本数据类型的成员变量,而比较复杂的类型的成员变量并没有像预期一样产生拷贝效果,这种拷贝我们就称之为“浅拷贝”
ii.深拷贝——如果要实现我们预期的对象拷贝效果,就需要使用深拷贝操作,其实在浅拷贝基础上实现深拷贝有两个步骤,以上边的代码为例:
[1]第一步:让AClass实现同样的clone功能
[2]第二步:在BClass的clone操作中多写入一句话:object.obj=(AClass)obj.clone();
对象克隆
在java面向对象的编程当中,要复制引用类型的对象,就必须克隆这些对象。通过调用对所有引用类型和对象都是可用的clone方法,来实现克隆。
如果是值类型的实例,那么“=”赋值运算符就可以将源对象的状态逐字节地复制到目标对象中。
要点
1>为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
2>在派生类中覆盖基类的clone(),并声明为public。
3>在派生类的clone()方法中,调用super.clone()。
4>在派生类中实现Cloneable接口。
5>Cloneable是一个没有抽象方法的标识接口。
建立一个本地拷贝
给一个对象建立本地拷贝的原因很可能是由于您计划修改该对象,并且您不想修改方法调用者的对象。假如您确定您需要一个本地拷贝,您能够使用Object类的clone()方法来执行这项操作。clone()方法被定义为受保护方法,但您必须在您希望克隆的任何子类中重新公开定义他。
例如,标准库类ArrayList忽略clone(),但您能够这样为ArrayList调用clone()方法:
importjava.util.*;classMyInt{
privateinti;
publicMyInt(intii){i=ii;}
publicvoidincrement(){i++;}
publicStringtoString(){
returnInteger.toString(i);
}
}publicclassTest{
publicstaticvoidmain(String[]args){
ArrayListal=newArrayList();
for(inti=0;i<10;i++)
al.add(newMyInt(i));
ArrayListal1=(ArrayList)al.clone();
//Incrementallal1'selements:
for(Iteratore=al1.iterator();e.hasNext();)
((MyInt)e.next()).increment();}
}
clone()方法生成一个Object,他必须重新转变为适当的类型。这个例子说明ArrayList的clone()方法如何不能自动克隆ArrayList包含的每一个对象——原有ArrayList和克隆后的ArrayList是相同对象的别名。
这种情况通常叫做浅拷贝,因为他仅仅复制一个对象的“表面”部分。实际的对象由这个“表面”,引用指向的任何对象,连同那些对象指向的任何对象等构成。这往往被称作“对象网络”。假如您拷贝任何这些内容,则被称为深拷贝。例如:
classDeeplyClone
{
publicstaticvoidmain(String[]args)
{
Professorp=newProfessor("feiyang",23);
Students1=newStudent("zhangshan",18,p);
Students2=(Student)s1.clone();
s2.p.name="Bill.Gates";
s2.p.age=30;
System.out.println("name="+s1.p.name+","+"age="+s1.p.age);
}
}
classProfessorimplementsCloneable
{
Stringname;
intage;
Professor(Stringname,intage)
{
this.name=name;
this.age=age;
}
publicObjectclone()
{
Objecto=null;
try
{
o=super.clone();
}
catch(CloneNotSupportedExceptione)
{
e.printStackTrace();
}
returno;
}
}
classStudentimplementsCloneable
{
Professorp;
Stringname;
intage;
Student(Stringname,intage,Professorp)
{
this.name=name;
this.age=age;
this.p=p;
}
publicObjectclone()
{
//Objecto=null;
Studento=null;
try
{
o=(Student)super.clone();
}
catch(CloneNotSupportedExceptione)
{
e.printStackTrace();
}
o.p=(Professor)p.clone();
returno;
}
}
例外
如果为一个不实现cloneable的类调用clone的话,那么就会抛出一个CloneNotSupportedException异常。相对于实现cloneable接口的类来说,如果为使用默认方法Object.clone的类的实例调用clone的话,就必须采取以下动作之一:
1.在clone的调用周围包装一个try代码块并捕捉到CloneNotSupportedException异常。
2.将异常CloneNotSupportedException添加到调用clone的方法的throws子句中,抛出这个异常。
面向对象
比如说,我们要用程序来描述一个人。如果是以往的结构化编程,我们可能会这样;
例如用C语言的话,可能会建立一个结构体:
structPerson{
姓名;
年龄;
等等;...
}
然后用定义的一些函数来描述他的行为。比如voidwalk(structp);voideat(structp);等等。
然后使用walk(p)来描述行走,使用eat(p)来描述吃饭等。
这样不利于程序结构的维护。开发效率也不高。
但是用java面向对象方式,这一切就显得自然了。我们建立一个类,表示人:
classPerson{
姓名
性别
体重
身高等..(人类都有的属性)
吃饭
睡觉等行为(也就是人类都有的行为)
}
然后将类产生一个实例,就产生了一个'人'的对象。
Personxiaobai=newPerson("小白",身高,体重...等参数);
如果要描述祖先后代的关系,很简单。只要让人类继承自Animal即可。
classAnimal{
......
}
classPersonextendsAnimal{
.......
}
这样动物有的属性和行为,人不用定义也可以拥有,符合自然规律~哈哈
面向对象不是java特有的,只是一种思想,如果你愿意,用结构化语言C语言也可以写出面向对象的代码
分享到:
相关推荐
在Java编程语言中,对象克隆是一种创建一个与原对象具有相同数据的新对象的过程。对象克隆主要用于复制或备份对象,以便在不干扰原始对象的情况下对其进行修改或操作。本篇文章将详细探讨Java中的对象克隆及其实现...
Java中的对象复制与克隆是程序开发中常见的需求,主要用于创建一个对象的副本,而不会影响原始对象的状态。这里主要讨论两种类型的对象拷贝:浅拷贝和深拷贝。 浅拷贝,也称为表面拷贝,是创建一个新的对象,然后将...
"Java 对象克隆详解" Java 对象克隆是 Java 编程中一个重要的概念。由于 Java 中的对象使用引用类型,所以没有直接的方法可以将对象的内容复制到一个新的对象。Java 提供了一个特殊的 clone() 方法,为所有的引用...
在Java编程语言中,克隆是一种创建对象副本的方法,它允许我们复制一个对象并拥有一个完全独立的新实例,而不是仅仅引用原始对象。克隆技术在处理复杂数据结构、避免对象共享以及实现对象复制等方面有着广泛的应用。...
在Java编程语言中,对象克隆是一种创建与现有对象具有相同数据的新对象的过程。这个过程在需要复制对象的所有属性而不创建新类型实例时非常有用。本文将深入探讨Java中的对象克隆,包括其原理、实现方式以及注意事项...
标题中的“java对象复制克隆”主要涉及的是深拷贝,这是一种创建一个新对象的方式,新对象不仅复制了原对象的所有属性,还复制了嵌套的对象引用,使得修改复制后的对象不会影响到原始对象。 **浅拷贝**:在浅拷贝中...
在Java编程语言中,克隆技术是一个重要的概念,它允许我们创建一个对象的精确副本,即一个全新的对象,它具有与原对象相同的属性值。这个副本通常可以独立于原始对象存在和修改。克隆技术在处理那些需要复制对象但又...
java的两种深度克隆方法,1cloneTest是用Cloneable接口的clone方法实现(对象必须要实现cloneable接口).2cloneSerialize.java是用对象流写对象到byte数组中,然后从byte数组中取得对象.(对象必须要实现serializble接口)
Java 中的克隆机制可以让我们方便地制造出一个对象的副本来,但是在克隆过程中需要注意浅克隆和深克隆的区别。 浅克隆(Shallow Clone)是指对对象的域进行简单的 copy,对象的reference变量也会被copy,但是对应的...
在Java编程语言中,克隆是一种创建对象副本的方法,它允许我们复制一个对象并得到一个与原对象相同但独立的新对象。克隆分为两种主要类型:深克隆和浅克隆。理解这两种克隆的区别是Java面向对象编程中的重要概念。 ...
在Java中,深度克隆是一种用于创建对象副本的方法,它可以确保复制出的新对象与原对象之间没有任何引用关系,也就是说,新对象中的所有成员变量(包括引用类型)都是原对象对应成员变量的副本。这种特性使得深度克隆...
本文将带领读者深入认识Java对象克隆的应用场景、实现机制以及克隆的利弊,从而加深对Java对象生命周期和数据安全的理解。 首先,何为克隆?克隆是指在内存中创建一个新的对象,该对象复制了原始对象的所有属性和值...
总的来说,理解Java对象的深克隆和浅克隆是优化代码和解决特定问题的关键。根据具体需求选择合适的克隆方式,可以提高代码的可维护性和灵活性。在设计类和系统时,应考虑对象复制的需求,并决定是否实现`Cloneable`...
在Java编程语言中,"深度克隆"是一个重要的概念,主要涉及到对象复制。深度克隆,也称为完全克隆,是指创建一个与原对象相同的新对象,不仅复制原对象的所有属性,还复制了原对象中引用的对象。这通常用于创建一个...
通过以上示例可以看出,在Java中实现对象的克隆并不复杂,但需要注意的是,对于含有其他可变对象的类来说,必须确保这些子对象也支持克隆,这样才能实现真正的深拷贝。此外,还需要注意异常处理以及类型转换等问题。...
可以更好的去理解java克隆的运用,尤其在多线程的运用过程中,多个对象进行操作过程中,可以先进行对 对象进行 备份,首先就克隆一份,当多线程对对象操作过程中,与异常情况,可以对对象进行恢复,克隆还其他的用途,学会...
在Java编程语言中,克隆是创建一个对象副本的过程,这个副本与原对象有相同的属性值,但作为不同的对象存在。克隆分为两种主要类型:浅克隆(Shallow Clone)和深克隆(Deep Clone)。这篇博客文章将探讨这两种克隆...
在Java编程语言中,克隆和序列化是两个重要的概念,它们在数据处理和对象管理中扮演着关键角色。下面将分别对这两个概念进行详细解释,并结合实例和源代码进行阐述。 **一、克隆** 1. **克隆定义**:克隆是指创建...
在Java编程语言中,克隆(Clone)机制是一种创建对象副本的方法,它允许开发者创建一个已有对象的新实例,这个新实例与原对象具有相同的属性值,但却是两个独立的对象,彼此的操作不会互相影响。克隆机制在某些情况...