Java参数传递到底是值传递还是引用传递?
2017-07-04 16:23
776 查看
“Java的参数传递到底是值传递还是引用传递?”这个问题在网上一直有争论,很多人也是云里雾里摸不着头脑,查阅网上的资料时也是鱼龙混杂,让人感觉高深莫测。其实这个问题一点也不难,下面我们先抛开值传递、引用传递的概念角度,从参数传递的原理来对这个问题进行分析。
★ “拷贝”是Java参数传递的核心所在!只要搞清楚“拷贝”是如何在参数传递中发挥作用的,那么“值传递还是引用传递”这个问题将迎刃而解。
参数传递无非就是传递两种类型:基本类型和引用类型。首先来看基本类型:
基本类型在传递时传递的是值的拷贝,在方法中改变的是值的拷贝,原值不会发生任何变化。如以下代码:
示例1:
输出结果为:
通过输出结果,我们发现int类型i的值没有被改变,在方法中被改变的是基本类型值的拷贝。
引用类型(也就是对象)在作为参数传递时传递的是对象所在内存地址的拷贝。看如下两个示例:
示例2:
输出结果为:
示例3:
输出结果为:
通过以上两个示例,我们发现示例2中传入的对象被方法更改了,而示例3中传入的对象没有被方法更改,这是为什么呢?我们通过示意图来解析其中的原理:
首先来看示例2,我们一步步的进行分析:
①在main方法中首先执行
0X11是假设对象所在的内存地址
②实例化ParameterTest2并且调用它的change()方法,编译器会拷贝一份sb对象的内存地址,将其传入方法中,拷贝的内存地址跟sb的内存地址完全相同,因此指向同一个字符串:
sbCopy是传入方法中的对象内存地址的拷贝
③change()方法中使用了StringBuffer的append()方法对字符串进行了扩展,由于原对象跟其拷贝指向同一个字符串,所以当这个字符串改变时,sb的内容肯定改变。
所以示例2中的sb对象内容发生了改变。
接下来看示例3,也是一步步进行分析:
①跟示例2相同,首先执行了
②实例化ParameterTest3并且调用它的change()方法,编译器拷贝一份sb对象的内存地址并将其传入方法中,在change()方法中执行
③使用append()方法对字符串进行扩展:
由于sb的内存拷贝重新指向了一个新的内存地址,所以当append()扩展了字符串的时候不会对原对象sb造成任何影响,所以输出结果里sb的内容没有发生改变。
部分参考自java参数传递(超经典)
★ “拷贝”是Java参数传递的核心所在!只要搞清楚“拷贝”是如何在参数传递中发挥作用的,那么“值传递还是引用传递”这个问题将迎刃而解。
参数传递无非就是传递两种类型:基本类型和引用类型。首先来看基本类型:
基本类型在传递时传递的是值的拷贝,在方法中改变的是值的拷贝,原值不会发生任何变化。如以下代码:
示例1:
public class ParameterTest1 { public void change(int i){ i = 100; } public static void main(String[] args) { int i = 20; System.out.println("before change:"+i); ParameterTest1 pt1 = new ParameterTest1(); pt1.change(i); System.out.println("after change:"+i); } } }
输出结果为:
通过输出结果,我们发现int类型i的值没有被改变,在方法中被改变的是基本类型值的拷贝。
引用类型(也就是对象)在作为参数传递时传递的是对象所在内存地址的拷贝。看如下两个示例:
示例2:
public class ParameterTest2 { public void change(StringBuffer sb){ sb.append(" luck"); } public static void main(String[] args) { ParameterTest2 pt2 = new ParameterTest2(); StringBuffer sb = new StringBuffer("good"); System.out.println("before change:"+sb); pt2.change(sb); System.out.println("after change:"+sb); } }
输出结果为:
示例3:
public class ParameterTest3 { public void change(StringBuffer sb){ sb = new StringBuffer("great"); sb.append(" luck"); } public static void main(String[] args) { StringBuffer sb = new StringBuffer("good"); System.out.println("before change:"+sb); ParameterTest3 pt3 = new ParameterTest3(); pt3.change(sb); System.out.println("after change:"+sb); } }
输出结果为:
通过以上两个示例,我们发现示例2中传入的对象被方法更改了,而示例3中传入的对象没有被方法更改,这是为什么呢?我们通过示意图来解析其中的原理:
首先来看示例2,我们一步步的进行分析:
①在main方法中首先执行
StringBuffer sb = new StringBuffer("good")这条语句,这时会产生一个sb字符串对象,并且sb的内容是“good”,也就是这个对象指向内存方法区中的字符串“good”。
0X11是假设对象所在的内存地址
②实例化ParameterTest2并且调用它的change()方法,编译器会拷贝一份sb对象的内存地址,将其传入方法中,拷贝的内存地址跟sb的内存地址完全相同,因此指向同一个字符串:
sbCopy是传入方法中的对象内存地址的拷贝
③change()方法中使用了StringBuffer的append()方法对字符串进行了扩展,由于原对象跟其拷贝指向同一个字符串,所以当这个字符串改变时,sb的内容肯定改变。
所以示例2中的sb对象内容发生了改变。
接下来看示例3,也是一步步进行分析:
①跟示例2相同,首先执行了
StringBuffer sb = new StringBuffer("good"),产生一个sb字符串对象。
②实例化ParameterTest3并且调用它的change()方法,编译器拷贝一份sb对象的内存地址并将其传入方法中,在change()方法中执行
sb = new StringBuffer("great"),sb内存地址拷贝重新new了一个StringBuffer对象,new会开辟一个新的内存空间,也就是说,sb内存地址拷贝指向了一个新的内存地址,如图所示:
③使用append()方法对字符串进行扩展:
由于sb的内存拷贝重新指向了一个新的内存地址,所以当append()扩展了字符串的时候不会对原对象sb造成任何影响,所以输出结果里sb的内容没有发生改变。
总结
那么问题来了,通过以上分析,Java参数传递到底是值传递还是引用传递?一般我们认为的引用传递是可以通过传引用参数来改变传入的参数的值(C++和C#就可以),而不会出现示例3的情况,归根到底,Java中传递的是拷贝,基本类型传递的是值的拷贝,引用类型传递的是内存地址的拷贝,当一个对象实例作为一个参数被传递到方法中时,参数的值就是对该对象的内存地址。所以Java的参数传递是值传递。部分参考自java参数传递(超经典)
相关文章推荐
- java参数传递时到底是值传递还是引用传递
- java面试题解惑:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
- 画重点,Java方法的参数到底是值传递还是引用传递?
- java面试题:当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
- java参数传递时到底是值传递还是引用传递
- Java - 当一个对象被当作参数传递到一个方法后,此方法可改变这个对象的属性,并可返回变化后的结果,那么这里到底是值传递还是引用传递?
- java到底是按值传递还是按引用传递?
- Java中函数参数的传递是值传递还是引用传递
- java 方法中参数是值传递还是引用传递
- Java中的参数传递到底是引用还是值传递?
- Java到底是值传递还是引用传递呢?(只有值传递)
- Java 把对象作为参数传到一个方法里,这个是值传递还是引用传递, 为什么结果这么怪?
- Java-String 到底是值传递还是引用传递
- JavaScript 函数参数传递到底是值传递还是引用传递
- Java中到底是值传递还是引用传递?
- Java中,String类型和包装类型作为参数传递时,是属于值传递还是引用传递呢?
- JavaScript 函数参数传递到底是值传递还是引用传递
- Java中函数参数的传递是值传递还是引用传递
- JavaScript 函数参数传递到底是值传递还是引用传递
- JAVA传参数到底是值传递还是引用