给⼀个对象赋值会随原来的对象变化关于java对象复制
clone(转)
问题如下
public static void main(String[] args){
User c1=new User();
c1.setId(1);
User c2=new User();
c2=c1;
System.out.Id());
c1.setId(2);
System.out.Id());
String s1="s1";
String s2="s2";
System.out.println(s2);
s2=s1;
s1="sss";
System.out.println(s2);
}
输出如下
1
2
s2
s1
关于java对象复制(转)
关于java对象复制
我们在编码过程经常会碰到将⼀个对象传递给另⼀个对象,java中对于基本型变量
采⽤的是值传递,⽽对于对象⽐如bean传递时采⽤的是应⽤传递也就是地址传递,
⽽很多时候对于对象传递我们也希望能够象值传递⼀样,使得传递之前和之后有
不同的内存地址,在这种情况下我们⼀般采⽤以下两种情况。
1 对象克隆
什么是"clone"?
在实际编程过程中,我们常常要遇到这种情况:有⼀个对象A,在某⼀时刻A中已经包含了⼀些有效值,此时可能会需要⼀个和A完全相同新对象B,并且此后对B任何改Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有⼀个⽅法clone()。JDK API的说明⽂档解释这个⽅法将
返回Object对象的⼀个拷贝。要说明的有怎样应⽤clone()⽅法?
⼀个很典型的调⽤clone()代码如下:
class CloneClass implements Cloneable{
public int aInt;
public Object clone(){
CloneClass o = null;
try{
o = (CloneClass)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
e.printStackTrace();
}
return o;
}
有三个值得注意的地⽅,⼀是希望能实现clone功能的CloneClass类实现了Cloneable接⼝,这个接⼝属于java.lang包,java.lang包已经被缺省的导⼊类中,所以不需要
应该说第三点是最重要的,仔细观察⼀下Object类的clone()⼀个native⽅法,native⽅法的效率⼀般来说都是远⾼于java中的⾮native⽅法。这也解释了为什么要⽤Obj 那么clone类为什么还要实现Cloneable接⼝呢?稍微注意⼀下,Cloneable接⼝是不包含任何⽅法的!其实这个接⼝仅仅是⼀个标志,⽽且这个标志也仅仅是针对Obje 什么是影⼦clone?
下⾯的例⼦包含三个类UnCloneA,CloneB,CloneMain。CloneB类包含了⼀个UnCloneA的实例和⼀个int类型变量,并且重载clone()⽅法。CloneMain类初始化UnC
package clone;
class UnCloneA {
private int i;
public UnCloneA(int ii) { i = ii; }
public void doubleValue() { i *= 2; }
public String toString() {
String(i);
}
}
class CloneB implements Cloneable{
public int aInt;
public UnCloneA unCA = new UnCloneA(111);
public Object clone(){
CloneB o = null;
try{
o = (CloneB)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
}
public class CloneMain {
public static void main(String[] a){
CloneB b1 = new CloneB();
b1.aInt = 11;
System.out.println("before clone,b1.aInt = "+ b1.aInt);
System.out.println("before clone,b1.unCA = "+ b1.unCA);
CloneB b2 = (CloneB)b1.clone();
b2.aInt = 22;
b2.unCA.doubleValue();
System.out.println("=================================");
System.out.println("after clone,b1.aInt = "+ b1.aInt);
System.out.println("after clone,b1.unCA = "+ b1.unCA);
System.out.println("=================================");
System.out.println("after clone,b2.aInt = "+ b2.aInt);
System.out.println("after clone,b2.unCA = "+ b2.unCA);
}
}
/** RUN RESULT:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 222
after clone,b1.unCA = 222
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222
*/
输出的结果说明int类型的变量aInt和UnCloneA的实例对象unCA的clone结果不⼀致,int类型是真正的被clone了,因为改变了b2中的aInt变量,对b1的aInt没有产⽣影响⼤多时候,这种clone的结果往往不是我们所希望的结果,这种clone也被称为"影⼦clone"。要想让b2.unCA指向与b2.unCA不同的对象,⽽且b2.unCA中还要包含b1.u 怎么进⾏深度clone?
把上⾯的例⼦改成深度clone很简单,需要两个改变:⼀是让UnCloneA类也实现和CloneB类⼀样的clone功能(实现Cloneable接⼝,重载clone()⽅法)。⼆是在Clone 程序如下:
;
class UnCloneA implements Cloneable{
private int i;
public UnCloneA(int ii) { i = ii; }
public void doubleValue() { i *= 2; }
public String toString() {
String(i);
}
public Object clone(){
UnCloneA o = null;
try{
o = (UnCloneA)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}
}
class CloneB implements Cloneable{
public int aInt;
public UnCloneA unCA = new UnCloneA(111);
public Object clone(){
CloneB o = null;
try{
o = (CloneB)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
o.unCA = (UnCloneA)unCA.clone();
clonereturn o;
}
}
public class CloneMain {
public static void main(String[] a){
CloneB b1 = new CloneB();
b1.aInt = 11;
System.out.println("before clone,b1.aInt = "+ b1.aInt);
System.out.println("before clone,b1.unCA = "+ b1.unCA);
CloneB b2 = (CloneB)b1.clone();
b2.aInt = 22;
b2.unCA.doubleValue();
System.out.println("=================================");
System.out.println("after clone,b1.aInt = "+ b1.aInt);
System.out.println("after clone,b1.unCA = "+ b1.unCA);
System.out.println("=================================");
System.out.println("after clone,b2.aInt = "+ b2.aInt);
System.out.println("after clone,b2.unCA = "+ b2.unCA);
System.out.println("after clone,b2.unCA = "+ b2.unCA);
}
}
/** RUN RESULT:
before clone,b1.aInt = 11
before clone,b1.unCA = 111
=================================
after clone,b1.aInt = 11
after clone,b1.unCA = 111
=================================
after clone,b2.aInt = 22
after clone,b2.unCA = 222
*/
可以看出,现在b2.unCA的改变对b1.unCA没有产⽣影响。此时b1.unCA与b2.unCA指向了两个不同的UnCloneA实例,⽽且在CloneB b2 = (CloneB)b1.clone();调⽤的
要知道不是所有的类都能实现深度clone的。例如,如果把上⾯的CloneB类中的UnCloneA类型变量改成StringBuffer类型,看⼀下JDK API中关于StringBuffer的说明,还要知道的是除了基本数据类型能⾃动实现深度clone以外,String对象是⼀个例外,它clone后的表现好象也实现了深度clone,虽然这只是⼀个假象,但却⼤⼤⽅便了通过以上我们可以看出在某些情况下,我们可以利⽤clone⽅法来实现对象只见的复制,但对于⽐较复杂的对象(⽐如对象中包含其他对象,其他对象⼜包含别的对象.
2 对象序列化
所谓对象序列化就是将对象的状态转换成字节流,以后可以通过这些值再⽣成相同状态的对象。这个过程也可以通过⽹络实现,可以先在Windows机器上创建⼀个对象也许你会说,只了解⼀点点,但从来没有接触过,其实未必如此。RMI、Socket、JMS、EJB你总该⽤过⼀种吧,彼此为什么能够传递J
ava对象,当然都是对象序列化第⼀次使⽤Java的对象序列化是做某项⽬,当时要求把⼏棵⾮常复杂的树(JTree)及相应的数据保存下来(就是我们常⽤的保存功能),以便下次运⾏程序时可以继续上那时XML技术在⽹上⾮常的热,⽽且功能也强⼤,再加上树的结构本来就和XML存储数据的格式很像。作为⼀项对新技术⽐较有兴趣的我当然很想尝试⼀下。不过经过还好,发现了Java的对象序列化机制,问题迎刃⽽解,只需简单的将每棵树的根节点序列化保存到硬盘上,下次再通过反序列化后的根节点就可以轻松的构造出和原来其实保存数据,尤其是复杂数据的保存正是对象序列化的典型应⽤。最近另⼀个项⽬就遇到了需要对⾮常复杂的数据进⾏存取,通过使⽤对象的序列化,问题同样化难对象的序列化还有另⼀个容易被⼤家忽略的功能就是对象复制(Clone),Java中通过Clone机制可以复制⼤部分的对象,但是众所周知,Clone有深层Clone和浅层Cl 还有就是Swing组件,如果你有两个很象很象(或是⼀模⼀样)的⽐较难以构造的Swing组件,你该怎么办,也许你想到了Clone,但是偏偏Java的Swing组件没有提供
ByteArrayOutputStream
byteOut = new ByteArrayOutputStream();
ObjectOutputStream out
= new ObjectOutputStream(byteOut);
out.writeObject(combo);
ByteArrayInputStream byteIn = new ByteArray());
ObjectInputStream in
=new ObjectInputStream(byteIn);
JComboBox comb2 = (adObject();
虽然Java的序列化⾮常简单、强⼤,但是要⽤好,还有很多地⽅需要注意。⽐如曾经序列化了⼀个对象,可由于某种原因,该类做了⼀点点改动,然后重新被编译,那你可以通过添加serialVersionUID属性来解决这个问题。如果你的类是个单态(Singleton)类,是否允许⽤户通过序列化机制复制该类,如果不允许你需要谨慎对待该
/**
* Clone Object
* @param obj
* @return
* @throws Exception
*/
private Object cloneObject(Object obj) throws Exception{
private Object cloneObject(Object obj) throws Exception{
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(obj);
ByteArrayInputStream byteIn = new ByteArray());        ObjectInputStream in =new ObjectInputStream(byteIn);
adObject();
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。