关于Java值传递还是引用传递以前概念不是很清楚,也看了很多文章,但是看完也是一知半解的,今天又人在群里发了一道题,经过思考后对于传递问题有了一些明白点了,所以进行记录。
在弄明白传递问题之前我们需要弄清楚以下几个问题:基本数据类型和引用数据类型区别?
基本数据类型分为三类:
1. 数值类型:byte,short,int,long,float,double
2. 布尔类型:boolean
3. 字符类型:character
引用数据类型:String,数组,class,interface
我们拿int和String举例说明不同:
int number=10;
String str="zcc";
我们可以从图中看到,在基本数据类型中变量中存放的是变量的值,在引用数据类型中变量存放的是地址,而这个地址指向变量的值。
好了我们开始正式解析
我们先尝试思考下面代码输出结果是什么?
public class ParamTest3 {
public void change(int a,int b){
int temp=a;
a=b;
b=temp;
}
public static void main(String[] args) {
int a=10,b=20;
System.out.println("未经过change处理"+a);
System.out.println("未经过change处理"+b);
ParamTest3 paramTest3 = new ParamTest3();
paramTest3.change(a,b);
System.out.println("经过change处理"+a);
System.out.println("经过change处理"+b);
}
}
结果:
未经过change处理10
未经过change处理20
经过change处理10
经过change处理20
我们发现即使经过了交换的处理我们的a,b值也并没有交换。那么这是为什么呢?
在main方法调用change(int a,int b)时,向a,b传递的是a,b值的副本,因此者两个a,b对应的内容不是一个,change方法中修改的只是自己栈中的内容,并没有修改main中的内容。
我们再来看看下面程序
public class DemoTest {
public static void main(String[] args) {
Person2 person2 = new Person2("阿大");
chage(person2);
System.out.println(person2.name);
}
public static void chage(Person2 p){
p = new Person2("阿小");
}
}
class Person2{
String name;
public Person2(String name){
this.name=name;
}
}
结果:
阿大
我们看看在堆中代码情况 如图:
在执行new Person(“阿大”)时在堆中开辟空间,person2持有该内存地址0x123如图一。随后执行chang(person2)方法,将person2作为实际参传递给形参p,注意这个时候传递的是地址的值将地址0x123给了p,如图二。然后执行p = new Person(“阿小”),此时会重新开辟一块0x456的内存赋值给p,如图三。所以输出的是— 阿大
我们先看看上面这种情况是否是引用传递?
首先这一定不是引用传递,如果是引用传递,那么在执行p = new Person(“阿小”)时person2应该指向的是0x456。
所以这应该是实际参数的引用的地址复制了一份给了形式参数,所以这应该是值传递,将引用地址作为值传递给了形式参数
再来分析下面代码
public class DemoTest {
public static void main(String[] args) {
Person2 person2 = new Person2("阿大");
chage(person2);
System.out.println(person2.name);
}
public static void chage(Person2 p){
p.name="阿小";
//p = new Person2("阿小");
}
}
class Person2{
String name;
public Person2(String name){
this.name=name;
}
}
结果
阿小
在堆中情况如下:
在这段代码中,并没有对形参进行修改,而是对形参地址中存储内容进行修改。
所以,我们在分析题的时候要明确实参究竟有没有复制一份给形参,如果是基本数据类型,那么就会复制一份给形参。如果传递的是一个地址,那么就要看这个地址有没有改变。
我们再看下面代码:
class ParamTest2{
public static void main(String[] args) {
ParamTest2 pt2 = new ParamTest2();
String name = "zcc";
pt2.pass(name);
System.out.println("print in main , name is " + name);
}
public void pass(String name) {
name = "zhangxiaochun";
System.out.println("print in pass , name is " +name);
}
}
结果:
print in pass , name is zhangxiaochun
print in main , name is zcc
很多人认为结果应该都是第一句,但是实际却并不是这样的。因为当我们在执行name = “zhangxiaochun”;时,本质上执行的时name = new String(“zhangxiaochun”);所以结果应该是不同的。
所以,Java是值传递。
如果是基本数据类型,传递的是基本数据类型的值的拷贝
如果是引用数据类型,传递的是地址值的拷贝。
最后留一个问题:
在这段代码中除了以这种方式输出阿小还有什么方式?(仅变动一行代码)
public class DemoTest {
public static void main(String[] args) {
Person2 person2 = new Person2("阿大");
chage(person2);
System.out.println(person2.name);
}
public static void chage(Person2 p){
p.name="阿小"; //输出阿小
//p = new Person2("阿小");
}
}
class Person2{
String name;
public Person2(String name){
this.name=name;
}
}