关于函数参数的引用和复制

newerz 2007-03-07 07:04:50
有如下程序,对于部分参数在调用函数时被复制(如:String, arry, Object(可能Object不算));有些被引用(如:HashMap)

想问下,那些类型的变量调用函数时被复制,哪些被引用?
多谢先!

--------------
import java.util.HashMap;

public class Test1 {

public static void main(String[] args) {
String s="s1";
Object o = "o1";
int[] a = new int[]{1,2,3};
HashMap h = new HashMap();
h.put("h1", "v");
f(s, o, a, h);
System.out.println("string=" + s);
System.out.println("object=" + o);
System.out.println("array=" + a.length);
System.out.println("hashmap=" + h.size());
}

static void f(String s, Object o, int[] a, HashMap h){
s +="__";
o = "222";
a = new int[]{1,2,3,4};
h.put("2", "v2");
}
}

-----------结果:
string=s1
object=o1
array=3
hashmap=2
...全文
650 17 打赏 收藏 转发到动态 举报
写回复
用AI写文章
17 条回复
切换为时间正序
请发表友善的回复…
发表回复
hailun 2007-03-08
  • 打赏
  • 举报
回复
做个标记
Dan1980 2007-03-07
  • 打赏
  • 举报
回复
只要是Object(包括数组和String),就都是引用。简单类型(int, char等)才会被复制。
xingyue2003 2007-03-07
  • 打赏
  • 举报
回复
int[] a = new int[]{1,2,3};

HashMap h = new HashMap();都是集合类型吧,
为什么前者是复制,后者是引用呢?
-------------------------------------------
麻烦说清楚点,new关键字是干什么的。
lhpapa 2007-03-07
  • 打赏
  • 举报
回复
int[] a = new int[]{1,2,3};

HashMap h = new HashMap();都是集合类型吧,
为什么前者是复制,后者是引用呢?
george_jiang212 2007-03-07
  • 打赏
  • 举报
回复
前者是数组的话也是引用,因为数组可以被看作是array对象
h.put("h1", "v");//v被引用
f(s, o, a, h);//s,o,a被复制,h被引用
h.put("2", "v2");//v2被引用
yeah920 2007-03-07
  • 打赏
  • 举报
回复
h.put("h1", "v");//v被引用
f(s, o, a, h);//s,o,a被复制,h被引用
h.put("2", "v2");//v2被引用
xingyue2003 2007-03-07
  • 打赏
  • 举报
回复
java的基本类型和string的对象会被复制,其他的是引用,如果前者是数组的话也是引用,因为数组可以被看作是array对象
newerz 2007-03-07
  • 打赏
  • 举报
回复
很感谢大家热情回复。
收获不少也解决了这个问题。特别是Dan1980的:简单类型和地址永远是复制的,而除此之外都是不复制的。
之前有这个困惑也是由于对String的不了解。很感谢Veryx和jianfengqu对String的解释。

Many thanks you all!
jianfengqu 2007-03-07
  • 打赏
  • 举报
回复
xingyue2003() ( ) 信誉:100 Blog 2007-3-7 8:32:01 得分: 0



java的基本类型和string的对象会被复制,其他的是引用,如果前者是数组的话也是引用,因为数组可以被看作是array对象
---------------------------------
不要误导人家,只有基本类型才是复制,String是类不会被复制.数组在java里是和类一样的不会被复制.



malligator 2007-03-07
  • 打赏
  • 举报
回复
我在h.put("2", "v2");后加了句new HashMap();但结果没边,这样看起来好像是复制,是吗?

==========
如果你是:
h = new HashMap();
h.put("2", "v2");
你将得到:
hashmap=1

感觉楼主是不是思维进死胡同了??
malligator 2007-03-07
  • 打赏
  • 举报
回复
全部都是引用。

string=s1 //因为函数中用=重新赋值了(new了新实例),改变了地址,不再指向原来实例了,下同
object=o1
array=3
hashmap=2 //因为函数中调用了类似于设置之类的方法,改变了内容
Dan1980 2007-03-07
  • 打赏
  • 举报
回复
to 楼主:

只要是类的实例,就不会被复制,String也一样,没有特殊性。数组虽然不是类的实例,但也是做为对象而存在的,所以也不会被复制。

被复制的类型只有简单类型,具体地说,是boolean, char, byte, short, int, long, float, double这八种。

另外,对象的引用(JAVA中叫引用,其实就是对象的地址,相当于C++的指针)本身是被复制的。这和C++中的指针会被复制是一个道理。

本质上,JAVA中所有的赋值操作以及函数的参数传递及值返回都是复制的。但对于简单类型和非简单类型,其复制的内容有所不同,对于简单类型复制的是对象本身,而对于非简单类型复制的是对象的地址。JAVA不允许程序员自己来选择是复制对象本身还是复制地址。

C++新手,有时甚至是有经验的程序员也往往要花大量时间来研究复制控制,而JAVA简化了所有的这些。在JAVA中,你只要记住:简单类型和地址永远是复制的,而除此之外都是不复制的。

JAVA提供一个复制非简单类型的方法,clone(),但这个方法也是复制对象的表层,对于所有的非简单类型对象成员都是复制其地址,clone()是一种“浅复制”。
Veryx 2007-03-07
  • 打赏
  • 举报
回复
String的这个特点很重要,这就是为什么我们总是使用String 做Map的key,因为它不会改变
原始类型的包装类也是这样的,也是做map的key的好东东,因为对象的改变会使它本身的hashCode改变,这样HashMap就会重新hash,
Veryx 2007-03-07
  • 打赏
  • 举报
回复
只要不是简单类型就会被引用,String和HashMap不同的地方是String是一个内容不可改变的对象,就是说如果你想改变一个String,你得到必然是一个新的String
可以看看lz的代码对4个变量的操作,前3个都是在赋值,最后是对map的put
f(String s, Object o, int[] a, HashMap h) 在调用这个方法的时候,s,o, a, h是在栈中的临时变量,也就是说只有在

这个方法的生命周期内才有效,(lz做c很多年应该知道传值和传地址的区别吧, 指针也是变量只不过我们操作他的规则很特

殊), 对前3个变量的操作都是对变量本身的操作(赋值), 没有对他们指向的对象做操作,又能期望那些对象有什么改变呢?
而对第4个的操作是对h这个变量指向的对象的操作( map.put() )
如果对第4个变量的操作也是h=new HashMap(); 那么结果就是什么也没有变化
sunnykun 2007-03-07
  • 打赏
  • 举报
回复
建议楼主看一下《thinking in java》,里面有一章对到底是引用还是复制做了非常详细的解释。
newerz 2007-03-07
  • 打赏
  • 举报
回复
多谢大家回复,可能我没有将问题讲清楚。
C和java都做了好多年了,指针、地址这些概念还是清楚的。
我想问在java这么多种类型里,那些类是会被复制的,那些类会被引用。(2种类的特征是什么)

To Dan1980:
为何String有其特殊性,从String的源代码哪里可看出。
HashMap和String都是同样继承Object为何有不同呢?

To mainGalaxy(天狼星):
我在h.put("2", "v2");后加了句new HashMap();但结果没边,这样看起来好像是复制,是吗?

Thanks!
  • 打赏
  • 举报
回复
楼主如果有一些c的基础也许容易理解一些。在java里面, 函数调用时, 参数传递的简单类型(int, char等)会被复制, 因此在函数中对这些参数的修改在函数退出是会丢失。参数传递的对象类型实际上传递的是引用, 也就是指针, 指针的本质也是一个整数, 因此这个引用会被复制一份, 但是这个引用指向的对象不会被复制。因此, 在函数中, 通过参数对对象的操作不会丢失, 但是对这个引用的重新赋值会丢失。 在你的代码中,

s +="__"; //这个是对s的重新赋值, 丢失
o = "222"; //同上
a = new int[]{1,2,3,4}; //同上
h.put("2", "v2"); //通过引用来操作对象, 不会丢失

62,614

社区成员

发帖
与我相关
我的任务
社区描述
Java 2 Standard Edition
社区管理员
  • Java SE
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧