值传递和引用传递
在说这个问题之前首先我们需要明确java中对象变量的存储:
例如:People p=new People();
首先在堆中建立People对象
然后在栈内存中建立变量p,并使p指向People对象在堆中的地址,也就是说p中保存的是People对象的堆地址,p为People对象的引用
当p作为函数参数时传递的是其保存的地址;
接下来我们看两个例子:
一、
public class RefrenceOrValue {
static void test1(StringBuffer str)
{
str=new StringBuffer("hello world");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuffer str=new StringBuffer("you are handsome");
System.out.println(str);
test1(str);
System.out.println(str);
}
}运行结果:
you are handsome
you are handsome
结果并没有改变str的值
二、
public class RefrenceOrValue {
static void test2(StringBuffer str)
{
str.append("str改变了");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
StringBuffer str=new StringBuffer("you are handsome");
System.out.println(str);
test2(str);
System.out.println(str);
}
}
结果:
you are handsome
you are handsomestr改变了
结果str的值改变了
分析:test1()和test2()中都接收了str的值,回顾对象的存储,str的值就是"you are handsome" 字符串对象的地址。在接收str值主要有下面的过程:成员变量str将它的值传递给形参str(注意:两个str并不是同一个变量,成员变量str是在堆内存中分配空间,而形参str是在栈中分配空间)但是这里传递的是对象的地址(类似c中的指针);
Test1()中str=new StringBuffer("hello world");实际上是将形参str的指向改变了,对成员变量str没有影响
test2()中str.append("str改变了")因为将实参(也就是成员变量str)的值传递给了形参str,所以实参和形参都同时指向了"you are handsome"这个对象,那通过两者更改他们指向的内容效果是一样的
主要抓住实参与形参是两个不同的变量,但是因为对象的引用保存的是对象的地址,所以通过实参与形参修改对象内容效果是一致的,但在函数体中又修改了形参的指向那就不能更改实参指向的对象了
将例一中的StringBuffer对象改为String类型对象其结果也不会改变,原理与上述相同,并不是因为String类型变量是一个固定值这个原因
public class RefrenceOrValue {
static void test1(String str)
{
str=new String("hello world");
}
public static void main(String[] args) {
// TODO Auto-generated method stub
String str="you are handsome";
System.out.println(str);
test1(str);
System.out.println(str);
}
}
结论:在java中对象作为形参时传递的是对象的引用值;对于这类问题还需要注意,实参与形参是不同的两个变量,形参为实参的浅拷贝也叫副本(即两者的指向相同),但形参的指向在函数体内部是可能改变的。浅拷贝可以参考博客中计算机基础内容