来自:https://www.cnblogs.com/xiaoxiaoyihan/p/4883770.html#autoid-0-0-0
回顾:
在程序设计语言中,将参数传递分为按值调用和按引用调用。按值调用:表示方法接收的是调用者提供的值。而按引用调用表示方法接收的是调用者提供的变量地址。
一个方法可以修改传递引用所对应的变量值,而不能修改传递值调用所对应的变量值。
Java总是采用按值调用。方法得到的是所有参数值的一个拷贝,特别的,方法不能修改传递给它的任何参数变量的内容。
方法参数共有两种类型:
- 基本数据类型
- 对象引用
1. 基本数据类型为参数
查看一下的代码:
public class ParamTest {
public static void main(String[] args) {
int price = 5;
doubleValue(price);
System.out.print(price);
}
public static void doubleValue(int x) {
x = 2 * x;
}
}
【输出结果】: 5
可以看到,这个方法执行之后,price的值并没有变化。接下来,看一下doubleValue具体的执行过程为:
- x被初始化为price值的一个拷贝,即5
- x乘以2后等于10。但是price没有变化,依然是5
- doubleValue执行完后,参数变量不再使用
2. 对象引用为参数
从上面的例子我们已经知道一个方法不能修改一个基本数据类型的参数。而对象引用作为参数就不同了。看下面的例子:
class Student {
private float score;
public Student(float score) {
this.score = score;
}
public void setScore(float score) {
this.score = score;
}
public float getScore() {
return score;
}
}
public class ParamTest {
public static void main(String[] args) {
Student stu = new Student(80);
raiseScore(stu);
System.out.print(stu.getScore());
}
public static void raiseScore(Student s) {
s.setScore(s.getScore() + 10);
}
}
【运行结果】:
90.0
可以看出,Student实例s的内容改变了。
具体执行过程为:
- s被赋予stu值的拷贝,这里是一个对象的引用
- raiseScore方法应用于这个应用。s和stu指向同一对象,该对象的分数增加了10
- raiseScore方法结束后,s不再使用,stu指向的那个对象分数增加了10
3. 对对象是值调用还是引用传递?
首先编写一个交换两个学生的方法:
public static void swap(Student x, Student y) {
Student temp = x;
x = y;
y = temp;
}
如果java对对象是采用的是引用传递,那个这个方法是可以的。那么x,y对象的分数是交换的。看下面的例子:
按 Ctrl+C 复制代码
按 Ctrl+C 复制代码
【运行结果】:
交换前:
a的分数:0.0--- b的分数:100.0
交换后:
a的分数:0.0--- b的分数:100.0
可以看出,两者并没有实现交换。说明引用传递的说法是不正确的。接下来一步一步看看swap调用的过程:
- 将对象a,b的拷贝分别赋值给x,y,此时a和x指向同一对象,b和y指向同一对象
- swap方法体完成x,y的的交换,此时a,b并没有变化
- 方法执行完成,x和y不再使用,a依旧指向new Student(0),b指向new Student(100)
首先,创建两个对象:
然后,进入方法体,将对象a,b的拷贝分别赋值给x,y:
接着,交换x,y的值:
swap执行完成,x,y不再使用,回到创建时状态。
从这个过程中可以看出,Java对对象采用的不是引用调用,实际上,对象引用进行的是值传递。
总结一下java中方法参数的使用情况:
- 一个方法不能修改一个基本数据类型的参数(即数值型和布尔型)
- 一个方法可以改变一个对象参数的状态
- 一个方法不能让对象参数引用一个新的对象
讲的比较透:https://blog.csdn.net/xiaosha009/article/details/50680199
前言
最近和同事讨论算法效率问题无意中涉及到一个问题,java中调用方法的时候是值传递呢?还是引用传递?网上搜索一下相关问题,众说纷纭,有人说值传递,有人说引用传递,还有人说”基础类型是值传递,对象类型是引用传递“。那么我们就用简单客观的代码分析一下。
值传递
值传递是指将该值复制一份出来使用,比如a复制一份a1出来,a1做的操作不会影响到a。例子如下:
public static void methodOne(int a) {
a++;
System.out.println("methodOne a="+a);
}
public static void main(String[] args) {
int a = 100;
methodOne(a);
System.out.println("main a="+a);
}
输出结果为:
methodOne a=101
main a=100
很明显这是值传递。不多解释。主要的问题出现在下面引用传递
引用传递
引用传递是将该值的地址传递给方法,比如取a的地址值b,b指向a,可以通过b找到a并对a进行修改。这时候a的值就会改变。废话不多说,上代码:
<span style="white-space:pre"> </span>public static void methodTwo(List<Integer> a) {
a.add(101);
}
public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
a.add(100);
methodTwo(a);
System.out.println("main a="+a.toString());
}
运行的结果如下:
main a=[100, 101]
这时候,很多人会说,看,java中的基本类型是值传递,对象类型是引用传递。如果这样认为的话,那就大错特错了。再来看看下面的代码:
<span style="white-space:pre"> </span>public static void methodTwo(List<Integer> a) {
a = new ArrayList<Integer>();// 就在这加了这一句
a.add(101);
}
public static void main(String[] args) {
List<Integer> a = new ArrayList<Integer>();
a.add(100);
methodTwo(a);
System.out.println("main a="+a.toString());
}
运行结果如下:
main a=[100]
这时候应该很多人就蒙逼了,这算闹哪样呀,不是引用传递吗?应该是main a=[101]才对的呀!现在我们静下来分析一下,java中方法之间传递对象参数的内存变化是怎样的?来,我们从代码一句一句分析下来。
<span style="white-space:pre"> </span>List<Integer> a = new ArrayList<Integer>();
这时候内存里边会有这样一个模型(图不是很漂亮,大家将就一下):
当调用methodTwo方法时,模型变如下:
这时候应该就清晰很多了,对象引用a被复制了一份出来使用,methodTwo拿到的是a的复制品。当methodTwo中调用
<span style="white-space:pre"> </span>a = new ArrayList<Integer>();
模型变化如下:
这时候应该都恍然大悟了吧。在new一个新的对象出来之后,methodTwo方法的a指向了新的对象实例,所以怎么改变都不会改变main方法中a的对象。同时也可以证明,java中只有值传递没有引用传递,在传递对象时,是传递对象的引用的副本,不是直接传递对象的引用本体。
总结
java这个特性应该很多人都不太了解,因为这种东西很少人去探究,敲代码敲多了,反反复复都是这样的语句,没有时间去思考也觉得没必要去思考。但一旦出现bug,就会难倒一堆人。一个小问题就会涉及到java底层的原理。
这是我个人第一篇技术博文,希望对你有所帮助。哈哈,第一篇呢,第一篇呢,有点小激动,每周一更,希望能做到。
(唉,这篇文章文字还是很少,因为本人语言功能性短缺,写的不好请多多指正,程序员看看图应该懂吧)