java基础之值传递和引用传递的区别

前言

首先说观点:java只有值传递没有引用传递

然后再来看看值传递与引用传递两者的定义

值传递(pass by value)是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。

引用传递(pass by reference)是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。

这里牢记值传递中将实际参数复制一份。

然后就是对于参数类型:值类型 和 引用类型。

结合起来理解就是:值类型传递,java是将其值内容复制一份给形参;对于引用类型传递,java是将其地址复制一份给形参。

下面结合实例深入理解为什么java只有值传递

public class 值传递 {  
public static void main(String[] args)  
{  
String str1="abc";  
updateStr1(str1);  
System.out.println("main函数中"+str1);  
}  
public static void updateStr1(String str1)  
{  
str1="cba"; //<注解>  
System.out.println("调用函数中"+str1);  
}  
  
}  
结果:

在这里插入图片描述
在这里我们能够清晰看到我们传递的是String类型的对象即(引用类型),并且在调用函数中我们修改了str1为cba,如果是引用传递那么我们在主函数打印则应该是cba,

但是很遗憾我们在主函数中仍然打印出来的是abc。所以我们可以说java是值传递类型了吗,答案是不完全的。

接下来再看这一段代码:

package 字符串;  
    
  
  public class person {   private int age;   public int getAge() { return age; } public void setAge(int age) { this.age = age; }  
  
}  
public class 值传递2 {  
public static void main(String[] args)  
{  
person p1=new person();  
p1.setAge(10);  
System.out.println("我在主函数里对p1的年龄属性赋值为"+p1.getAge());  
setage(p1);  
System.out.println("我再从主函数里获取P1的年龄属性"+p1.getAge());  
}  
  
public static void setage(person p1)  
{  
p1.setAge(18); //不是我们对它的地址进行了操作,而是我们对它地址的内容进行了操作  
System.out.println("我在调用函数里对p1的年龄属性重新赋值为"+p1.getAge());  
}  
  
}  

结果:
在这里插入图片描述

咦,怎么回事这次也是传递的对象(引用类型),为什么这次我们对年龄这个字段的修改在主函数同步了呢?

别急,下面我们先来分析这两个例子。

首先第一个类型的例子中,我们传递的是String类型的变量,它是一个特殊的类型的引用变量。

(不可变字符串:编译器可让字符串共享,即将各种字符串存放于公共存储池中,字符串变量是指向其中相应位置 --出自《Java核心技术 卷1》)

出于这句话的理解就是每个字符串都对应一个地址:我们例一中是将str1的地址复制给了我们的形参str1,并且形参中str1的地址进行了改变指向了“cba”的地址。所以说在主函数中的str1的地址仍然指向的是“abc”所对应的地址。

所以说对于String类型的变量,我们对于给它重新赋值不是改变了它的内容,而是改变了它指向字符串的位置。这也就解释了为什么java中String类型是不可变类型。

而在我们例二中,我们将p1的地址复制给了我们形参中的p1,此时他们都指向的内存中一块相同的地址这里存放着相同内容,所以我们在调用函数对这个地址中的内容进行修改时就会同步到我们主函数中的p1。所以这个并不意味着这个是引用传递。

好吧,那怎么才能解释好Java确实是值传递呢(上面String类型例子是特殊的引用类型不方便解释)

下面我们通过这个例子说明:

package 字符串;  
public class person {  
private int age;  
public int getAge() {  
return age;  
}  
public void setAge(int age) {  
this.age = age;  
}  
  
}  
public class 值传递3 {  
public static void main(String[] args) {  
person p1=new person();  
person p2=new person();  
p1.setAge(10);  
p2.setAge(18);  
System.out.println("我在主函数里对p1的年龄属性赋值为"+p1.getAge());  
System.out.println("我在主函数里对p2的年龄属性赋值为"+p2.getAge());  
swap(p1,p2);  
System.out.println("************我是主函数里的分割线***************");  
//我再在主函数里分别对p1,p2获取他们的年龄,若为引用传递则p1的年龄应该为18,p2为10.  
System.out.println("我在主函数里获取p1的年龄"+p1.getAge());  
System.out.println("我在主函数里获取p1的年龄"+p2.getAge());  
}  
public static void swap(person p1,person p2)  
{  
System.out.println("************我是调用函数里的分割线***************");  
person temp=new person();  
temp=p1;  
p1=p2;  
p2=temp;  
System.out.println("我在调用函数里交换了p1和p2指向的地址");  
System.out.println("我在调用函数里对p1的年龄属性赋值为"+p1.getAge());  
System.out.println("我在调用函数里对p2的年龄属性赋值为"+p2.getAge());  
  
}  
  
}  

结果:
在这里插入图片描述

看到没,这就是充分说明Java是值传递的例子。在这个例子中我们依然传递的是person类的对象p1,p2(引用类型),他们将各自的地址复制一份到了形参p1、p2。

然后我们在调用函数中交换了他们的地址,确实在调用函数中他们的age属性发生交换。但是再当我们在主函数获取他们的age时,如果是引用传递则应该p1的age为18,p2的age为10,

和我们在调用函数中打印结果一致。但是,很遗憾在主函数中他们的值仍然是p1(10),p2(18)。所以这也充分印证了java是值传递。

那么什么是引用传递呢?
实参传递给形参的是参数对于 堆内存上的引用地址 实参和 形参在内存上指向 了同一块区域 对形参的修改会影响实参
在这里插入图片描述

如果你还有点晕,不妨我们来看看下面两张图。
在这里插入图片描述

在这里插入图片描述




发布了40 篇原创文章 · 获赞 6 · 访问量 1490

猜你喜欢

转载自blog.csdn.net/qq_26737667/article/details/91398154