| 网站首页 | 业界新闻 | 小组 | 威客 | 人才 | 下载频道 | 博客 | 代码贴 | 在线编程 | 编程论坛
欢迎加入我们,一同切磋技术
用户名:   
 
密 码:  
共有 834 人关注过本帖
标题:[分享]JAVA中的指针,引用及对象的clone(转帖加个人思考)
只看楼主 加入收藏
しΟν∈→鱈
Rank: 1
等 级:新手上路
威 望:2
帖 子:369
专家分:0
注 册:2006-10-25
收藏
 问题点数:0 回复次数:11 
[分享]JAVA中的指针,引用及对象的clone(转帖加个人思考)
第一个例子:JAVA中的参数处理方式

class Obj{
String str = "init value";
public String toString(){
return str;
}
}
public class ObjRef{
Obj aObj = new Obj();
int aInt = 11;
public void changeObj(Obj inObj){
inObj.str = "changed value";
}
public void changePri(int inInt){
inInt = 22;
}
public static void main(String[] args)
{
ObjRef oRef = new ObjRef();

System.out.println("Before call changeObj() method: " + oRef.aObj);
oRef.changeObj(oRef.aObj);
System.out.println("After call changeObj() method: " + oRef.aObj);
System.out.println("==================Print Primtive=================");
System.out.println("Before call changePri() method: " + oRef.aInt);
oRef.changePri(oRef.aInt);
System.out.println("After call changePri() method: " + oRef.aInt);
}
}
/* RUN RESULT
Before call changeObj() method: init value
After call changeObj() method: changed value
==================Print Primtive=================
Before call changePri() method: 11
After call changePri() method: 11
*
*/
结论一:

从这个例子知道Java对对象和基本的数据类型的处理是不一样的。和C语言一样,当把Java的基本数据类型(如int,char,double等)作为入口参数传给函数体的时候,传入的参数在函数体内部变成了局部变量,这个局部变量是输入参数的一个拷贝,所有的函数体内部的操作都是针对这个拷贝的操作,函数执行结束后,这个局部变量也就完成了它的使命,它影响不到作为输入参数的变量。这种方式的参数传递被称为"值传递"。而在Java中用对象的作为入口参数的传递则缺省为"引用传递",也就是说仅仅传递了对象的一个"引用",这个"引用"的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。

第二个例子:Hashtable真的能存储对象吗?
import java.util.*;
public class HashtableAdd{
public static void main(String[] args){
Hashtable ht = new Hashtable();
StringBuffer sb = new StringBuffer();
sb.append("abc,");
ht.put("1",sb);
sb.append("def,");
ht.put("2",sb);
sb.append("mno,");
ht.put("3",sb);
sb.append("xyz.");
ht.put("4",sb);

int numObj=0;
Enumeration it = ht.elements();
while(it.hasMoreElements()){
System.out.print("get StringBufffer "+(++numObj)+" from Hashtable: ");
System.out.println(it.nextElement());
}
}
}


/* RUN RESULT
get StringBufffer 1 from Hashtable: abc,def,mno,xyz.
get StringBufffer 2 from Hashtable: abc,def,mno,xyz.
get StringBufffer 3 from Hashtable: abc,def,mno,xyz.
get StringBufffer 4 from Hashtable: abc,def,mno,xyz.
*/
结果很明显不可以

结论二:把对象时作为入口参数传给函数,实质上是传递了对象的引用

第三个例子:影子Clone
class UnCloneA {
private int i;
public UnCloneA(int ii) { i = ii; }
public void doubleValue() { i *= 2; }
public String toString() {
return Integer.toString(i);
}
}
class CloneB implements Cloneable{
public int aInt;
public UnCloneA unCA = new UnCloneA(111);
public CloneB 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,b2.aInt = 22
after clone,b2.unCA = 222
*/

结论三:int类型的变量aInt和UnCloneA的实例对象unCA的clone结果不一致,int类型是真正的被clone了,因为改变了b2中的aInt变量,对b1的aInt没有产生影响,也就是说,b2.aInt与b1.aInt已经占据了不同的内存空间,b2.aInt是b1.aInt的一个真正拷贝。相反,对b2.unCA的改变同时改变了b1.unCA,很明显,b2.unCA和b1.unCA是仅仅指向同一个对象的不同引用!从中可以看出,调用Object类中clone()方法产生的效果是:先在内存中开辟一块和原始对象一样的空间,然后原样拷贝原始对象中的内容。对基本数据类型,这样的操作是没有问题的,但对非基本类型变量,我们知道它们保存的仅仅是对象的引用,这也导致clone后的非基本类型变量和原始对象中相应的变量指向的是同一个对象。

(要了解深度Clone,请自已去查找相关资料,基实就是在上面例子中让CloneA也实现在Cloneable这个接口)

最后一个例子:Clone中String和StringBuffer的区别
class CloneC implements Cloneable{
public String str;
public StringBuffer strBuff;
public CloneC clone(){
CloneC o = null;
try{
o = (CloneC)super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
}
return o;
}

}
public class StrClone {
public static void main(String[] a){
CloneC c1 = new CloneC();
c1.str = new String("initializeStr");
c1.strBuff = new StringBuffer("initializeStrBuff");
System.out.println("before clone,c1.str = "+ c1.str);
System.out.println("before clone,c1.strBuff = "+ c1.strBuff);

CloneC c2 = (CloneC)c1.clone();
c2.str = c2.str.substring(0,5);   
//个人对于下面结论四中的蓝色部分感觉有问题。试写如下代码,注释掉前面那句。
c2.str = "hello"; //如果真如他所说,那这里的改变应该影响到c1.str的输出,但实际没有。。而如果我们写如下代码:
CloneC c3 = c1;
c3.str = "hello i'm c3 here"; //则输出的结果只对c1有影响,c2.str没有变,也就是说c2真正实现在跟基本数据类型一样的Clone,而不是一个引用!!!我不知道我是不是理解对了,但他的解释是肯定错掉了,还请那位达达来解释哈!
c2.strBuff = c2.strBuff.append(" change strBuff clone");
System.out.println("=================================");
System.out.println("after clone,c1.str = "+ c1.str);
System.out.println("after clone,c1.strBuff = "+ c1.strBuff);
System.out.println("=================================");
System.out.println("after clone,c2.str = "+ c2.str);
System.out.println("after clone,c2.strBuff = "+ c2.strBuff);
}
}
/* RUN RESULT
before clone,c1.str = initializeStr
before clone,c1.strBuff = initializeStrBuff
=================================
after clone,c1.str = initializeStr
after clone,c1.strBuff = initializeStrBuff change strBuff clone
=================================
after clone,c2.str = initi
after clone,c2.strBuff = initializeStrBuff change strBuff clone
*
*/
结论四:String类型的变量好象已经实现了深度clone,因为对c2.str的改动并没有影响到c1.str!难道Java把Sring类看成了基本数据类型?其实不然,这里有一个小小的把戏,秘密就在于c2.str = c2.str.substring(0,5)这一语句!实质上,在clone的时候c1.str与c2.str仍然是引用,而且都指向了同一个String对象。但在执行c2.str = c2.str.substring(0,5)的时候,它作用相当于生成了一个新的String类型,然后又赋回给c2.str。这是因为String被Sun公司的工程师写成了一个不可更改的类(immutable class),在所有String类中的函数都不能更改自身的值。
搜索更多相关主题的帖子: JAVA clone 指针 转帖 对象 
2007-02-05 01:43
gioxiao
Rank: 1
等 级:新手上路
帖 子:35
专家分:0
注 册:2006-10-14
收藏
得分:0 

对象引用和基本数据类型在栈上分配...而对象在堆上分配..
如果类里有基本数据类型的话,那么分配栈内存的时候,相当与是C中的一个结构体..
入口是对象引用的地址..
CloneC c3 = c1, c3这个对象引用就是c1.2者除了名字不同,其余的完全一致的..
clone一个对象时,对象引用是处于不同的栈空间,除了基本数据之外,指向同一个堆内存.
c3.str = "hello i'm c3 here"; 那么等于是c3.str指向了"hello i'm c3 here";
但是c3.str先前指向的字符串呢?它仍然在堆内存中,因为String是final...
c1和c3是同一个引用,,c2则不是..
所以c2.str仍然指向开始的那个字符串..而c1和c3是同一个引用,所以c1.str就是c3.str..
所以被改变了...
呵呵,不知道俺说的对不对,俺也只是在学java前学过一个月c....

2007-02-05 06:55
Java
Rank: 1
等 级:新手上路
帖 子:718
专家分:0
注 册:2007-1-29
收藏
得分:0 
楼上的文章不错,建议初学者仔细体会体会

Java,My Love!
2007-02-05 09:22
しΟν∈→鱈
Rank: 1
等 级:新手上路
威 望:2
帖 子:369
专家分:0
注 册:2006-10-25
收藏
得分:0 
别光看啊  也对我的问题发表下意见啊

开开心心的过&玩每一天!!!!
2007-02-05 11:03
Java
Rank: 1
等 级:新手上路
帖 子:718
专家分:0
注 册:2007-1-29
收藏
得分:0 
你没有问题啊,不错啊,见解也挺好啊

Java,My Love!
2007-02-05 11:09
しΟν∈→鱈
Rank: 1
等 级:新手上路
威 望:2
帖 子:369
专家分:0
注 册:2006-10-25
收藏
得分:0 

开开心心的过&玩每一天!!!!
2007-02-05 11:16
Java
Rank: 1
等 级:新手上路
帖 子:718
专家分:0
注 册:2007-1-29
收藏
得分:0 
不要脸红,确实是不错的

好好努力吧

Java,My Love!
2007-02-05 11:19
しΟν∈→鱈
Rank: 1
等 级:新手上路
威 望:2
帖 子:369
专家分:0
注 册:2006-10-25
收藏
得分:0 
呵呵  最近本来是学JSP  结果没学到什么。。。到是复习以前的东西。。
看到这  感觉不错 就帖上来了  希望能对新人有帮助

开开心心的过&玩每一天!!!!
2007-02-05 11:58
Java
Rank: 1
等 级:新手上路
帖 子:718
专家分:0
注 册:2007-1-29
收藏
得分:0 
学JAVA不能好高骛远,先把J2SE打扎实了再说


Java,My Love!
2007-02-05 12:25
parkxie111
Rank: 1
等 级:新手上路
帖 子:13
专家分:0
注 册:2006-11-10
收藏
得分:0 
'白发老爹'说的对!一定要好好琢磨!第三天开始!
2007-02-05 23:30
快速回复:[分享]JAVA中的指针,引用及对象的clone(转帖加个人思考)
数据加载中...
 
   



关于我们 | 广告合作 | 编程中国 | 清除Cookies | TOP | 手机版

编程中国 版权所有,并保留所有权利。
Powered by Discuz, Processed in 0.017061 second(s), 9 queries.
Copyright©2004-2024, BCCN.NET, All Rights Reserved