在Java中参数的传递主要有两种:值传递和引用传递
值传递
实参传递给形参的是值
形参和实参在内存上是两个独立的变量
对形参做任何修改不会影响实参
也就是说:在方法调用时,传入方法内部的是实参引用的拷贝,因此对形参的任何操作都不会影响到实参。
public class Main {
public static void main(String[] args) {
int b =20;
// 实参 实际上的参数
change(b);
System.out.println(b);
}
public static void change(int a){//形参 形式上的参数
a = 100;
}
}
结果:20
形参只是实参创建的一个副本,副本改变了,原本当然不可能跟着改变;
引用传递
实参传递给形参的是参数对于堆内存上的引用地址
实参和形参在内存上指向了同一块区域
对形参的修改会影响实参
public class Main {
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
System.out.println(list1);
change(list1);
System.out.println(list1);
}
public static void change(List<Integer> list2) {
list2.add(6);
}
}
结果: [2, 3, 4, 5] [2, 3, 4, 5, 6]
可以在IDEA上debug以下,如图:
从debug的结果可以看出,创建出来的list1的对象ID是484,list2的对象ID也是484,传过去的参数其实是list1的对象ID**。**
由于引用传递,传递的是地址,方法改变的都是同一个地址中的值。
原来list1指向0xxx地址,有4个数字,后来在change方法对0xxx地址添加了一个数字,变成了5个数字,地址都是指向同一块内存。
两者区别
- 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
- 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对引用对象进行操作会同时改变原对象.
Java到底是值传递还是引用传递
在Java方法中参数列表有两种类型的参数,基本类型和引用类型。
- **基本类型:**值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
- **引用数据类型:**指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。
这两种类型都是将外面的参数变量拷贝一份到局部变量中,基本类型为值拷贝,引用类型就是将引用地址拷贝一份。
网上众说纷纭,说什么的都有,但是我倾向于Java的传递是值传递
如果传的时基本数据类型,只改变传递的副本不会改变原变量;如果传递的时对象类型,传递的变量是对象类型的地址,修改此地址指向的对象值 = 直接去对地址指向的对象,但是不会修改原对象的引用
比如:交换两个对象
public class Main {
public static void swapObjectReference(ParamObject object1, ParamObject object2) {
ParamObject temp = object1;
object1 = object2;
object2 = temp;
}
public static void main(String[] args) {
ParamObject a = new ParamObject(true, 1);
ParamObject b = new ParamObject(false, 2);
System.out.println("a : " + a + " b : " + b);
swapObjectReference(a, b);
System.out.println("a : " + a + " b : " + b);
}
}
结果:
a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}
a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}
有了上面的知识之后,我们会发现这个方法中的引用地址交换,只不过是一个把戏而已,只是对方法中的两个局部变量的对象引用值进行了交换,不会对原变量引用产生任何影响的。
当然,完全说Java是值传递也不是严谨的,毕竟值传递的概念是:在方法调用时,传入方法内部的是实参引用的拷贝,因此对形参的任何操作都不会影响到实参。但是Java中有引用类型也就是包装类型的对象传递,传递其实是地址,在方法中修改形参会影响到实参的,因为形参和实参指向堆中同一块内存。
可以借鉴之前看到的一个解释:
java 使用的是一种名为值传递的求值策略,这种策略在传值过程中会复制实参的引用,并将这份拷贝传入到方法形参中,所以对形参的任何重赋值操作都不会对实参产生影响。
在Java中参数的传递主要有两种:值传递和引用传递
值传递
实参传递给形参的是值
形参和实参在内存上是两个独立的变量
对形参做任何修改不会影响实参
也就是说:在方法调用时,传入方法内部的是实参引用的拷贝,因此对形参的任何操作都不会影响到实参。
public class Main {
public static void main(String[] args) {
int b =20;
// 实参 实际上的参数
change(b);
System.out.println(b);
}
public static void change(int a){//形参 形式上的参数
a = 100;
}
}
结果:20
形参只是实参创建的一个副本,副本改变了,原本当然不可能跟着改变;
引用传递
实参传递给形参的是参数对于堆内存上的引用地址
实参和形参在内存上指向了同一块区域
对形参的修改会影响实参
public class Main {
public static void main(String[] args) {
List<Integer> list1 = new ArrayList<>();
list1.add(2);
list1.add(3);
list1.add(4);
list1.add(5);
System.out.println(list1);
change(list1);
System.out.println(list1);
}
public static void change(List<Integer> list2) {
list2.add(6);
}
}
结果: [2, 3, 4, 5] [2, 3, 4, 5, 6]
可以在IDEA上debug以下,如图:
从debug的结果可以看出,创建出来的list1的对象ID是484,list2的对象ID也是484,传过去的参数其实是list1的对象ID**。**
由于引用传递,传递的是地址,方法改变的都是同一个地址中的值。
原来list1指向0xxx地址,有4个数字,后来在change方法对0xxx地址添加了一个数字,变成了5个数字,地址都是指向同一块内存。
两者区别
- 值传递是对基本型变量而言的,传递的是该变量的一个副本,改变副本不影响原变量.
- 引用传递一般是对于对象型变量而言的,传递的是该对象地址的一个副本, 并不是原对象本身 。 所以对引用对象进行操作会同时改变原对象.
Java到底是值传递还是引用传递
在Java方法中参数列表有两种类型的参数,基本类型和引用类型。
- **基本类型:**值存放在局部变量表中,无论如何修改只会修改当前栈帧的值,方法执行结束对方法外不会做任何改变;此时需要改变外层的变量,必须返回主动赋值。
- **引用数据类型:**指针存放在局部变量表中,调用方法的时候,副本引用压栈,赋值仅改变副本的引用。但是如果通过操作副本引用的值,修改了引用地址的对象,此时方法以外的引用此地址对象当然被修改。(两个引用,同一个地址,任何修改行为2个引用同时生效)。
这两种类型都是将外面的参数变量拷贝一份到局部变量中,基本类型为值拷贝,引用类型就是将引用地址拷贝一份。
网上众说纷纭,说什么的都有,但是我倾向于Java的传递是值传递
如果传的时基本数据类型,只改变传递的副本不会改变原变量;如果传递的时对象类型,传递的变量是对象类型的地址,修改此地址指向的对象值 = 直接去对地址指向的对象,但是不会修改原对象的引用
比如:交换两个对象
public class Main {
public static void swapObjectReference(ParamObject object1, ParamObject object2) {
ParamObject temp = object1;
object1 = object2;
object2 = temp;
}
public static void main(String[] args) {
ParamObject a = new ParamObject(true, 1);
ParamObject b = new ParamObject(false, 2);
System.out.println("a : " + a + " b : " + b);
swapObjectReference(a, b);
System.out.println("a : " + a + " b : " + b);
}
}
结果:
a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}
a : ParamObject{flg=true, num=1} b : ParamObject{flg=false, num=2}
有了上面的知识之后,我们会发现这个方法中的引用地址交换,只不过是一个把戏而已,只是对方法中的两个局部变量的对象引用值进行了交换,不会对原变量引用产生任何影响的。
当然,完全说Java是值传递也不是严谨的,毕竟值传递的概念是:在方法调用时,传入方法内部的是实参引用的拷贝,因此对形参的任何操作都不会影响到实参。但是Java中有引用类型也就是包装类型的对象传递,传递其实是地址,在方法中修改形参会影响到实参的,因为形参和实参指向堆中同一块内存。
可以借鉴之前看到的一个解释:
java 使用的是一种名为值传递的求值策略,这种策略在传值过程中会复制实参的引用,并将这份拷贝传入到方法形参中,所以对形参的任何重赋值操作都不会对实参产生影响。
- 本文作者:
- 原文链接:
- 版权声明: 本博客所有文章除特别声明外,均采用 进行许可。转载请署名作者且注明文章出处。